AWS SDK Unity 2019

AWS SDK Unity 2019
5th April 2020 13 Comments Tutorial Marcus Lam

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.

About The Author
Marcus Lam An Electrical Engineer with programming skill in Hong Kong. Provide technical solutions for hardware or software projects.
Leave Comment
  1. 1

    Peter Mavronicolas

    Harvey the Electrical Engineer from Hong Kong,

    You’re awesome for making the AWS SDK.

    Thank you 😊

    Peter Mavronicolas
    Founder
    Whoa Apps Inc
    [email protected]

    Reply
  2. 1

    Rob Brooks

    Thank you for making available your rebuilt 2019-compatible AWS dlls, Marcus.
    I was having issues with callbacks not firing after calling Async functions and just replacing the AWSSDK.Core.dll with yours appears to have fixed my problems.
    Might it be possible to share your changes so that I can update my own SDK project.
    I’m presuming it’s possibly just a change to AndroidInterop.cs but I’ve been unable to find a fixed copy of this file.
    Many thanks.
    Rob.

    Reply
    1. 1

      Marcus Lam

      Yes, you are right. You may find the changed AndroidInterop.cs file here:
      https://lhkmarcus.com/post_src/AndroidInterop.cs

      I updated the post too.

      Reply
  3. 1

    Marcus Lam

    Yes, you are right. You may find the changed AndroidInterop.cs file here:
    https://lhkmarcus.com/post_src/AndroidInterop.cs

    Reply
  4. 1

    John

    Thanks for doing this Marcus. I tried using those .dll’s with .NET 2 standard will no luck. I also tried .NET 4.x in Unity to no avail. but better progress. I also had to swap the contents you show here between the link and awsconfig xml files.

    I get this error:
    ExecutionEngineException: Attempting to call method ‘UnityEngine.AndroidJavaObject::Get’ for which no ahead of time (AOT) code was generated.
    04-19 13:46:26.426 23861 23906 E Unity : at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in :0
    04-19 13:46:26.426 23861 23906 E Unity : at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in :0
    04-19 13:46:26.426 23861 23906 E Unity : at Amazon.Util.Internal.AndroidInterop.GetJavaField[T] (System.Object androidJavaObject, System.String methodName) [0x00000] in :0
    04-19 13:46:26.426 23861 23906 E Unity : at Amazon.Util.Internal.AmazonHookedPlatformInfo.Init () [0x00000] in :0
    04-19 13:46:26.426 23861 23906 E Unity : at Amazon.Util.Internal.AmazonHookedPlatformInfo.get_Instance () [0x00000] in :0
    04-19 13:46:26.426 23861 23906 E Unity : at Amazon.UnityInitializer.Awake () [0x00000] in <000000000000000000000

    Have you seen this before? I'm unable to secure a Congnito IdentityID like before.

    Reply
    1. 1

      Marcus Lam

      Did your app works in unity editor?

      Reply
  5. 1

    stewart

    Hi I am also getting the error:

    05-07 21:55:39.275 30636 30677 E Unity : ExecutionEngineException: Attempting to call method ‘UnityEngine.AndroidJavaObject::Get’ for which no ahead of time (AOT) code was generated.
    05-07 21:55:39.275 30636 30677 E Unity : at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at Amazon.Util.Internal.AndroidInterop.GetJavaField[T] (System.Object androidJavaObject, System.String methodName) [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at Amazon.Util.Internal.AmazonHookedPlatformInfo.Init () [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at Amazon.Util.Internal.AmazonHookedPlatformInfo.get_Instance () [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at Amazon.UnityInitializer.Awake () [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at UnityEngine.GameObject.AddComponent[T] () [0x00000] in :0
    05-07 21:55:39.275 30636 30677 E Unity : at Amazon.UnityInitializ
    05-07 21:55:39.278 30636 30677 I Unity : Attached unity initializer to FirehoseProvider

    Works fine in editor but not Android
    This is using Unity 2019.1…

    The only package I add in my project is:
    AWSSDK.Kinesis.3.3.100.173.unitypackage

    Any idea why I may be getting this error?
    Thanks

    Reply
    1. 1

      Marcus Lam

      Did you replace all the dll including AWSSDK.Core.dll?

      Reply
  6. 1

    Stewart

    Hi, yes I replaced just the AWSSDK.Core.dll and tried with also replacing AWSSDK.Core.pdb

    I also tried updating to use the package AWSSDK.Kinesis.3.3.100.173 and then swapping these dlls but the same error occurs

    Reply
    1. 1

      Marcus Lam

      You would need to replace all the dll that in the AWS_SDK_Unity2019.zip.
      It is because if you are using the AWSSDK that newer then the version of my build, it may not work.
      If you are using the AWSSDK.Kinesis, you would need to replace at least:
      AWSSDK.CognitoIdentity.dll
      AWSSDK.Core.dll
      AWSSDK.Kinesis.dll
      AWSSDK.SecurityToken.dll

      Reply
  7. 1

    Stewart

    Hi,

    Yes I actually just tried that, replacing them all with yours (those 4 you listed) and it has the same issue. Works fine in editor but Android has the “Attempting to call method ‘UnityEngine.AndroidJavaObject::Get’ for which no ahead of time (AOT) code was generated.” error.

    Not quite sure why that didn’t work. I may need to make the changes manually myself to see the process.

    Reply
    1. 1

      Marcus Lam

      You may find the AWSSDK code link below this post to build your own SDK.

      Reply
  8. 1

    Devi

    Hello,
    I have followed your steps and your solution works great for Unity + android with mono scripting backend but I need it to be working for IL2CPP.
    Can you please help

    Reply

Leave a reply

Your email address will not be published. Required fields are marked *

Translate »