Marcus Lam
Expert in R&D
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.
AWS Console:
https://console.aws.amazon.com/console/
The official AWS Unity SDK:
https://docs.aws.amazon.com/mobile/sdkforunity/developerguide/what-is-unity-plugin.html
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.
<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>
Download: https://lhkmarcus.com/post_src/link.xml
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.
<?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>
Download: https://lhkmarcus.com/post_src/awsconfig.xml
You may need to change the “us-east-1” to the region that you are using.
This setting should work in Unity 2018 and Unity 2019 “Editor” and “iOS”, BUT NOT the Android device. To work on the Android device, you would need to fix the AWS SDK (the next topic).
If you have an error about Amazon.AWSConfigs.set_HttpClient, you may add the code below in the “Start” of the program.
AWSConfigs.HttpClient = AWSConfigs.HttpClientOption.UnityWebRequest;
After you follow the official AWS SDK page steps (including import the official SDK) and setup the awsconfig.xml and link.xml.
Now your project should be work in both iOS and Android.
If you want it also work in Android IL2CPP, you would need to add the following code to your class:
#if UNITY_ANDROID
public void UsedOnlyForAOTCodeGeneration() {
//Bug reported on github https://github.com/aws/aws-sdk-net/issues/477
//IL2CPP restrictions: https://docs.unity3d.com/Manual/ScriptingRestrictions.html
//Inspired workaround: https://docs.unity3d.com/ScriptReference/AndroidJavaObject.Get.html
AndroidJavaObject jo = new AndroidJavaObject("android.os.Message");
int valueString = jo.Get<int>("what");
}
#endif
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
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.
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
peter@whoaapps.com
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.
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.
Marcus Lam
Yes, you are right. You may find the changed AndroidInterop.cs file here:
https://lhkmarcus.com/post_src/AndroidInterop.cs
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.
Marcus Lam
Did your app works in unity editor?
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
Marcus Lam
Did you replace all the dll including AWSSDK.Core.dll?
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
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
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.
Marcus Lam
You may find the AWSSDK code link below this post to build your own SDK.
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
Marcus Lam
Set up a “link.xml” file as described on the Unity SDK readme, which is necessary if you will be building with assembly stripping or IL2CPP. Be sure to add the line
https://github.com/aws/aws-sdk-net/blob/master/Unity.README.md#unity-sdk-fundamentals
Marcus Lam
Not sure if you still need AWS to be working for IL2CPP.
Try to put this code into your class(you do not need to change anything in this code):
#if UNITY_ANDROID(“what”);
public void UsedOnlyForAOTCodeGeneration() {
AndroidJavaObject jo = new AndroidJavaObject(“android.os.Message”);
int valueString = jo.Get
}
#endif
Enosh
Hello
Thanks for your precious posting.
You saved my week
may god bless you
Joe
Hi mate,
Thanks for this post. I am doing an Oculus Quest project research, and I try to use your modified SDK. When I follow your tutorial it works well (even the android version), but when I integrate it to the project it fails at some point.
So the connexion to the DynamoDB is working well as I am able to create a table, but then when I try to load Data it fails.
I get 6 errors, I put here only the last one:
“AmazonDynamoDBException making request PutItemRequest to https://dynamodb.eu-west-2.amazonaws.com/. Attempt 1.
UnityEngine.Debug:LogError(Object)
Amazon.Runtime.Internal.Util.UnityDebugLogger:Error(Exception, String, Object[])
Amazon.Runtime.Internal.Util.Logger:Error(Exception, String, Object[])
Amazon.Runtime.Internal.RetryHandler:LogForError(IRequestContext, Exception)
Amazon.Runtime.Internal.RetryHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.CallbackHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.EndpointResolver:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.Marshaller:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.CallbackHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.ErrorCallbackHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.MetricsHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.PipelineHandler:InvokeSync(IExecutionContext)
Amazon.Runtime.Internal.RuntimePipeline:InvokeSync(IExecutionContext)
Amazon.Runtime.AmazonServiceClient:Invoke(AmazonWebServiceRequest, InvokeOptionsBase)
Amazon.DynamoDBv2.AmazonDynamoDBClient:PutItem(PutItemRequest)
Amazon.DynamoDBv2.DocumentModel.Table:PutItemHelper(Document, PutItemOperationConfig)
Amazon.DynamoDBv2.DocumentModel.c__DisplayClass89_0:b__0()
Amazon.DynamoDBv2.c__DisplayClass1_0`1:b__0(Object)
System.Threading._ThreadPoolWaitCallback:PerformWaitCallback()”
Marcus Lam
I guess that is related to the link.xml or the awsconfig.xml or the AWS Console setting.
For the link.xml or the awsconfig.xml file, I am using “us-east-1” in this tutorial. You would need to change all the “us-east-1” to your region “eu-west-2”.
You would need to change the GameObject inspector too.
For the AWS Console setting, please watch my video in this post.
Joe
Yes, I did that. Actually, I think I know what is wrong. There is 2 AndroidManifest.XML in my project, The Quest one and yours.
Both as MAIN, which is wrong. As AWS should work on the background (the player doesn’t need to see anything from AWS) I have to merge both Manifest and remove the MAIN from your manifest.
If you have any idea how to do that, that would be great? Thanks
Ps: Of course I already watched your video (several times lolll), liked it and subscribed 😉
Marcus Lam
If you do not duplicate the setting in the AndroidManifest.XML(maybe “activity” in this case).
You may not need to have only one AndroidManifest.XML in your project.
Unity would combine the AndroidManifest.XML for you.
You may see this for the detail: https://docs.unity3d.com/Manual/android-manifest.html
John
I forgot to precise that the oculus manifest overwrites your file in: Assets/Plugins/Android/AndroidManifest.xml, which is the same manifest used by your plugin.
I need to merge them but have no idea how
osama
Hi I’m using unity 2020.1.0f1 , with IL2CPP with .Net Standard 2.0 , using latest aws-sdk-unity_3.3.802.0,but its not work for me on build its works on editor I followed all ur steps , I have facebook sdk but which add their dependencies on AndroidManifest.xml Located Asset/Plugin/Android, then I resolved dependencies now added aws dependency there, well I didn’t replace dlls files in which you have given , should i do it , I did it , but it didn’t allow me to build android w/o replace its complete build but sdk doesn’t work ,did you test on latest unity? It revert my project then follow ur steps many times , but no luck , can you guide me , what m i missing ? while as I said I’m using aws-sdk-unity_3.3.802.0 sdk should i replace dlls ? sorry for many words , but I need help
Daniel
Thank you, your guide literally saved me, I could not find info about it anywhere else.
Holyarm
Oh… God…
You saved my life.
jmgxgxgbf
AWS SDK Unity 2019 with fixed dll – Indie developer Marcus Lam
H
Hi,
Do you know how to make CognitoIdentityProvider to work with Unity ?
Thanks for this, been using your sdk to access DynamoDB!!