2020年4月25日 星期六

AWS SDK Unity 2019

If you have read and followed the official AWS SDK webpage, but you can not make it work in Unity 2019. I could help you here.
First, the AWS SDK should work in Unity 2018. If it does not work, please check the awsconfig.xml and link.xml setup. You may put those files under Assets\Resources. Here is the example for awsconfig.xml and link.xml.

link.xml

<?xml version="1.0" encoding="utf-8"?> 
<aws correctForClockSkew="true" region="us-east-1"> 
<logging logTo="UnityLogger" logResponses="Always" logMetrics="true" logMetricsFormat="JSON" /> 
<s3 useSignatureVersion4="true" /> </aws>
You may need to change the "us-east-1" to the region that you are using.

awsconfig.xml

<linker>
<!-- if you are using AWSConfigs.HttpClient.UnityWebRequest option-->
<assembly fullname="UnityEngine">
 <type fullname="UnityEngine.Networking.UnityWebRequest" preserve="all" />
 <type fullname="UnityEngine.Networking.UploadHandlerRaw" preserve="all" />
 <type fullname="UnityEngine.Networking.UploadHandler" preserve="all" />
 <type fullname="UnityEngine.Networking.DownloadHandler" preserve="all" />
 <type fullname="UnityEngine.Networking.DownloadHandlerBuffer" preserve="all" />
</assembly>
<assembly fullname="mscorlib">
 <namespace fullname="System.Security.Cryptography" preserve="all"/>
</assembly>
<assembly fullname="System">
 <namespace fullname="System.Security.Cryptography" preserve="all"/>
</assembly>
<assembly fullname="AWSSDK.Core" preserve="all"/>
<assembly fullname="AWSSDK.CognitoIdentity" preserve="all"/>
<assembly fullname="AWSSDK.SecurityToken" preserve="all"/>
<assembly fullname="AWSSDK.DynamoDBv2" preserve="all"/>
</linker>
In this example I am using the DynamoDB service so I add the <assembly fullname="AWSSDK.DynamoDBv2" preserve="all"/> . You should add the service that you are going to use here.
This setting should work in Unity 2018 and Unity 2019 "Editor" and "iOS", BUT NOT the Android device.

How to fix the AWS SDK for Unity 2019

After you follow the official AWS SDK page steps (including import the official SDK) and setup the awsconfig.xml and link.xml.
  1. Found and open the AndroidManifest.xml file which is under the "Assets\Plugins\Android".
  2. Change the "com.unity3d.player.UnityPlayerNativeActivity" to "com.unity3d.player.UnityPlayerActivity"
  3. Download the fixed SDK here https://lhkmarcus.com/AWS_SDK_Unity2019.zip
  4. Unzip and replace all the file to the Assets\AWSSDK in your unity project
Now your project should be work in both iOS and Android.

Build your own AWS SDK for Unity

You may want to build your own SDK if you are using other versions of AWS SDK. First you may found the AWS SDK code here: https://github.com/aws/aws-sdk-net. Then you may just change the AndroidInterop.cs that in your project. The AndroidInterop.cs file is under "aws-sdk-net-master\sdk\src\Core\Amazon.Util\Internal_unity". The file may look like this:

/*
 * Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 * 
 *  http://aws.amazon.com/apache2.0
 * 
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;

namespace Amazon.Util.Internal
{
    /// <summary>
    /// This class is used to make Android Java calls as an alternative to using Android macro's
    /// The class uses reflection but doesnto cache the PropertyInfo and MethodInfo, 
    /// so it should be sparingly used so as not to impact performance.
    /// </summary>
    public class AndroidInterop
    {
        /// <summary>
        /// The API makes a call to a static java method on a class and returns a typed parameter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="className"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static T CallStaticJavaMethod<T>(string className, string methodName, params object[] parameters)
        {
            Type androidJavaClassType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaClass");
            if (androidJavaClassType != null)
            {
                var javaUnityHelper = Activator.CreateInstance(androidJavaClassType, className);
                var callStaticMethod = androidJavaClassType.GetMethods()
                  .Where(x => x.Name == "CallStatic")
                  .FirstOrDefault();
                if (callStaticMethod != null)
                {
                    return (T)callStaticMethod.Invoke(javaUnityHelper, new object[] { methodName, parameters });
                }
            }
            return default(T);
        }

        /// <summary>
        /// The API makes a call to a static java method on a class and returns an object of Type AndroidJavaObject
        /// </summary>
        /// <param name="className"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static object GetJavaObjectStatically(string className, string methodName)
        {
            Type androidJavaClassType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaClass");
            Type androidJavaObjectType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaObject");
            if (androidJavaClassType != null)
            {
                var javaClass = Activator.CreateInstance(androidJavaClassType, className);
                var callStaticMethod = androidJavaClassType.GetMethods()
                    .Where(x => x.Name == "CallStatic")
                    .First(x => x.ContainsGenericParameters);

                var genericStaticMethod = callStaticMethod.MakeGenericMethod(androidJavaObjectType);

                return genericStaticMethod.Invoke(javaClass, new object[] { methodName, new object[] { } });
            }
            return null;
        }

        /// <summary>
        /// This API makes a call to a method on an Object by passing the specified parameters and returns a typed parameter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="androidJavaObject"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static T CallMethod<T>(object androidJavaObject, string methodName, params object[] parameters)
        {
            var method = androidJavaObject.GetType().GetMethods().Where(x => x.Name == "Call").First(x => x.ContainsGenericParameters);
            var genericMethod = method.MakeGenericMethod(typeof(T));
            return (T)genericMethod.Invoke(androidJavaObject, new object[] { methodName, parameters });
        }

        /// <summary>
        /// This API makes a call to a method on an Object by passing the specified parameters and returns an object of type AndroidJavaObject
        /// </summary>
        /// <param name="androidJavaObject"></param>
        /// <param name="methodName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object CallMethod(object androidJavaObject, string methodName, params object[] parameters)
        {
            Type androidJavaObjectType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaObject");
            var method = androidJavaObject.GetType().GetMethods()
                .Where(x => x.Name == "Call")
                .First(x => x.ContainsGenericParameters);
            var genericMethod = method.MakeGenericMethod(androidJavaObjectType);
            return genericMethod.Invoke(androidJavaObject, new object[] { methodName, parameters });
        }

        /// <summary>
        /// This API get a typed value from a static field 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="className"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static T GetStaticJavaField<T>(string className, string methodName)
        {
            Type androidJavaClassType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaClass");
            if (androidJavaClassType != null)
            {
                var javaUnityHelper = Activator.CreateInstance(androidJavaClassType, className);
                var staticGetter = androidJavaClassType.GetMethod("GetStatic");
                var genericGetter = staticGetter.MakeGenericMethod(typeof(T));

                if (genericGetter != null)
                {
                    return (T)genericGetter.Invoke(javaUnityHelper, new object[] { methodName });
                }
            }

            return default(T);
        }

        /// <summary>
        /// This API returns a value of type AndroidJavaObject from a static field
        /// </summary>
        /// <param name="className"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static object GetStaticJavaField(string className, string methodName)
        {
            Type androidJavaClassType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaClass");
            Type androidJavaObjectType = InternalSDKUtils.GetTypeFromUnityEngine("AndroidJavaObject");
            if (androidJavaClassType != null)
            {
                var javaUnityHelper = Activator.CreateInstance(androidJavaClassType, className);
                var staticGetter = androidJavaClassType.GetMethod("GetStatic");
                var genericGetter = staticGetter.MakeGenericMethod(androidJavaObjectType);

                if (genericGetter != null)
                {
                    return genericGetter.Invoke(javaUnityHelper, new object[] { methodName });
                }
            }
            return null;
        }

        /// <summary>
        /// This API returns a value of type AndroidJavaObject from a field on an android java object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="androidJavaObject"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static T GetJavaField<T>(object androidJavaObject, string methodName)
        {
            var method = androidJavaObject.GetType().GetMethods().Where(x => x.Name == "Get").First(x => x.ContainsGenericParameters);
            var genericMethod = method.MakeGenericMethod(typeof(T));
            return (T)genericMethod.Invoke(androidJavaObject, new object[] { methodName });
        }

        /// <summary>
        /// Returns an AndroidJavaObject 
        /// </summary>
        /// <returns></returns>
        public static object GetAndroidContext()
        {
            return GetStaticJavaField("com.unity3d.player.UnityPlayer", "currentActivity");
        }

    }
}

The problem is the androidJavaObject.GetType().GetMethods().Where(). After Unity 2019.1, It requires AndroidJavaObject[] but not the object[]. You may find the fixed AndroidInterop.cs here: https://lhkmarcus.com/post_src/AndroidInterop.cs

AWS SDK Unity 2019

Note


In most of the case, you just replace the AWSSDK.Core.dll would work. If your other dll (ex: AWSSDK.S3.dll, AWSSDK.DynamoDBv2.dll ) is too new/old that not match with the AWSSDK.Core.dll I uploaded, you may need to replace the other dll too.

2020年1月31日 星期五

建立自己的個人網頁


你是自顧人士或Indie Developer嗎?
我也是,請看看我的個人網頁:
https://lhkmarcus.com/


我只用了一天時間建立這個網頁
作為自顧人士需要以有限的時間達成可觀的效果
以下是我用來上存網頁和編輯網頁的工具
https://www.hostg.xyz/aff_c?offer_id=6&aff_id=28604

連結包含優惠碼,請在有效期間使用