Your SlideShare is downloading. ×
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Avoid loss of hair while coding Unity3D plugins for mobile
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Avoid loss of hair while coding Unity3D plugins for mobile

1,591

Published on

by Valerio “Lotti” Riva – Interactive Project …

by Valerio “Lotti” Riva – Interactive Project
Talk held on Codemotion Tech Meetup #4 - Rome Summer Edition

Published in: Technology, Art & Photos
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,591
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
11
Comments
0
Likes
7
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Valerio “Lotti” Riva – Interactive Project valerio.riva@gmail.com @ValerioRiva http://it.linkedin.com/in/valerioriva/ Avoid loss of hair while coding Unity3D plugins for mobile ROME 24 June 2014 – Valerio Riva Codemotion Tech Meetup #4 – Roma Summer Edition
  • 2. Nice to meet you! • Web / Game developer • Recent works @ Interactive Project • World Cup Juggler • OverVolt: crazy slot cars ROME 24 June 2014 – Valerio Riva 2
  • 3. Why develop a Unity3D mobile plugin? • Access to device native features • Implement third-party SDK (analytics, advertising, in-app purchases, game services, etc.) • Save/Earn money • Personal growth ROME 24 June 2014 – Valerio Riva 3
  • 4. Extending Unity 4.x • Unity supports C/C++ libraries. “extern”-alized functions/methods can be called from C# • All plugins must be placed inside “Assets/Plugins” folder • Platform-dependent plugins must be placed inside specific folders (x86, x86_64, Android, iOS, WP8, Metro, etc.) • Available only on Unity3D Pro/Mobile ROME 24 June 2014 – Valerio Riva 4
  • 5. Extending Unity (iOS) • Call externalized Object-C methods • Must wraps third-party SDK if their methods are not externalized • Gameobjects can receive messages from native code • Receiver methods declared on GO’s components must have only 1 string parameter as signature ROME 24 June 2014 – Valerio Riva 5
  • 6. Extending Unity (Android) • Use JNI (Java Native Interface), Unity provides Helper classes • Call native methods directly from Unity • Gameobjects can receive messages from native code • Receiver methods declared on GO’s components must have only 1 string parameter as signature • On specific cases, Unity Player activity must be extended • Android Manifest editing is often required ROME 24 June 2014 – Valerio Riva 6
  • 7. Extending Unity (WP8) • Access native code directly from Unity • Use of callbacks to return data from native code • Unity’s Mono (v2.6) doesn’t support .NET >= 4.0 • Artefacts are needed to use .NET >= 4.0 libaries • “Always” needs a fake and a real plugin – Unity will overwrite fake one with the real one automatically • In specific cases, write a plugin is a monkey job ROME 24 June 2014 – Valerio Riva 7
  • 8. Extending Unity (remarks) • Scripting define symbols are your friends • Native calls are CPU intensive • Provide fake results for in-editor usage • Every native UI call must run inside native UI thread • Every callback must run inside Unity thread (WP8) • Save time by testing plugin on a native app • Remember to include Unity library if needed • classes.jar • UnityEngine.dll ROME 24 June 2014 – Valerio Riva 8
  • 9. Case study: Flurry plugin • Wrap Flurry SDK to made it accessible from Unity • Flurry SDK is simple to use, just call static methods (Advertising, In-App Purchase, …, are more complex plugin) • We have to code wrappers for each platform • Place platforms SKDs on the right directories • FlurryAnalytics-4.0.0.jar -> Plugins/Android/ • libFlurry_5.0.0.a -> Plugins/iOS/ • FlurryWP8SDK.dll -> Plugins/WP8/ • FlurryWP8SDK.dll -> Plugins/ (the WP8 fake one) ROME 24 June 2014 – Valerio Riva 9
  • 10. Flurry plugin (iOS) • Flurry SDK is not “extern”-alized • Dictionary<string, string> must be translated somewhat to NSMutableDictionary • Each KeyValuePair<string,string> are concatenated to form a single string ROME 24 June 2014 – Valerio Riva 10 //FlurryiOS.h - created by PRADA Hsiung on 13/3/8. extern "C" { void FlurryiOS_startSession(unsigned char* apiKey); void FlurryiOS_setEventLoggingEnabled(BOOL bEnabled); void FlurryiOS_logEventWithParameters(unsigned char* eventId,unsigned char *parameters); }
  • 11. Flurry plugin (iOS) // FlurryiOS.m - created by Faizan Naqvi on 1/10/13. #import <stdio.h> #include "Flurry.h" //Flurry SDK headers void FlurryiOS_startSession(const char* apiKey) { NSString *str = [NSString stringWithUTF8String:apiKey]; [Flurry startSession:str]; } void FlurryiOS_setEventLoggingEnabled(BOOL bEnabled){ [Flurry setEventLoggingEnabled:bEnabled]; } ROME 24 June 2014 – Valerio Riva 11
  • 12. Flurry plugin (iOS) void FlurryiOS_logEventWithParameters(const char* eventId,const char *parameters) { NSString *params = [NSString stringWithUTF8String:parameters]; NSArray *arr = [params componentsSeparatedByString: @"n"]; NSMutableDictionary *pdict = [[[NSMutableDictionary alloc] init] autorelease]; for(int i=0;i < [arr count]; i++) { NSString *str1 = [arr objectAtIndex:i]; NSRange range = [str1 rangeOfString:@"="]; if (range.location!=NSNotFound) { NSString *key = [str1 substringToIndex:range.location]; NSString *val = [str1 substringFromIndex:range.location+1]; //NSLog(@"kv %@=%@n",key,val); [pdict setObject:val forKey:key]; } } if([pdict count]>0) { [Flurry logEvent:[NSString stringWithUTF8String:eventId] withParameters:pdict timed:false]; } else FlurryiOS_logEvent(eventId); } ROME 24 June 2014 – Valerio Riva 12
  • 13. Flurry plugin (iOS) Meanwhile on Unity side… #region FlurryiOS_Imports [DllImport("__Internal", CharSet = CharSet.Ansi)] private static extern void FlurryiOS_startSession([In, MarshalAs(UnmanagedType.LPStr)]string apiKey); [DllImport("__Internal")] private static extern void FlurryiOS_setEventLoggingEnabled(bool bEnabled); [DllImport("__Internal", CharSet = CharSet.Ansi)] private static extern void FlurryiOS_logEventWithParameters([In, MarshalAs(UnmanagedType.LPStr)]string evendId, [In, MarshalAs(UnmanagedType.LPStr)]string parameters); #endregion ROME 24 June 2014 – Valerio Riva 13
  • 14. Flurry plugin (WP8) • Flurry SDK is compiled with .NET 4.5, import it and Unity will go mad! • We need the “fake & real” library approach, but… • Using Flurry SDK doesn’t involve use of complex logic or complex user defined classes… • … we can use the downloaded FlurryWP8SDK.dll as “real” • and code only the fake dll! Yes, this is the particular case where you can bring in monkeys! ROME 24 June 2014 – Valerio Riva 14
  • 15. Flurry plugin (WP8) using FlurryWP8SDK.Models; using System; using System.Collections.Generic; namespace FlurryWP8SDK.Models { public enum Gender { Unknown = -1, Female = 0, Male = 1 } public class Parameter { public Parameter(string name, string value) { Name = name; Value = value; } public string Name { get; set; } public string Value { get; set; } } } namespace FlurryWP8SDK { public sealed class Api { private static Api instance = null; public static Api Current { get { return instance; } } public void DummyInitiator() {} public static void EndSession() {} public static void EndTimedEvent(string eventName) {} public static void EndTimedEvent(string eventName, List<Parameter> parameters) {} public static void LogEvent(string eventName) {} public static void LogEvent(string eventName, List<Parameter> parameters, bool timed) {} public static void SetAge(int age) {} public static void SetGender(Gender gender) {} public static void SetLocation(double latitude, double longitude, float accuracy) {} public static void SetSessionContinueSeconds(int seconds) {} public static void StartSession(string apiKey) {} } } ROME 24 June 2014 – Valerio Riva 15 That was easy, now give me peanuts!
  • 16. Flurry plugin (Android) • As said before, Flurry doesn’t involve complex logic… • … so we save time and wrote plugin directly in Unity using JNI Helper classes ROME 24 June 2014 – Valerio Riva 16 public Flurry StartSession(string apiKey) { #if !UNITY_EDITOR && UNITY_WP8 Api.StartSession(apiKey); #elif !UNITY_EDITOR && UNITY_ANDROID using(AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) using(AndroidJavaObject obj_Activity = cls_UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) using(AndroidJavaClass cls_FlurryAgent = new AndroidJavaClass("com.flurry.android.FlurryAgent")) { cls_FlurryAgent.CallStatic("onStartSession", obj_Activity, apiKey); } #elif !UNITY_EDITOR && UNITY_IPHONE FlurryiOS_startSession(apiKey); #endif return this; }
  • 17. Flurry plugin (Android) ROME 24 June 2014 – Valerio Riva 17 public Flurry LogEvent(string eventId, Dictionary<string,string> parameters, bool timed) { #if !UNITY_EDITOR && UNITY_WP8 List<Parameter> p = new List<Parameter>(); foreach(KeyValuePair<string,string> i in parameters) { p.Add(new Parameter(i.Key,i.Value)); } Api.LogEvent(eventId, p, timed); #elif !UNITY_EDITOR && UNITY_ANDROID using(AndroidJavaObject obj_HashMap = new AndroidJavaObject("java.util.HashMap")) { // Call 'put' via the JNI instead of using helper classes to avoid: "JNI: Init'd AndroidJavaObject with null ptr!" IntPtr method_Put = AndroidJNIHelper.GetMethodID(obj_HashMap.GetRawClass(), "put“, "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); object[] args = new object[2]; foreach(KeyValuePair<string, string> kvp in parameters) { using(AndroidJavaObject k = new AndroidJavaObject("java.lang.String", kvp.Key)) using(AndroidJavaObject v = new AndroidJavaObject("java.lang.String", kvp.Value)) { args[0] = k; args[1] = v; AndroidJNI.CallObjectMethod(obj_HashMap.GetRawObject(), method_Put, AndroidJNIHelper.CreateJNIArgArray(args)); } } cls_FlurryAgent.CallStatic("logEvent", eventId, obj_HashMap, timed); } #elif !UNITY_EDITOR && UNITY_IPHONE FlurryiOS_logEventWithParametersTimed(eventId, dictionaryToText(parameters)); #endif return this; }
  • 18. and for more complex plugins…? • Do most of logic on native side to minimize native calls from Unity • Messages examples (Android) UnityPlayer.UnitySendMessage("gameObjectName", "methodName", "message"); • Use “Action<…>” delegates to pass callbacks on WP8, Unity supports Action with max 4 parameters as .NET 3.5 does • Structure plugin as a wrapper (mainly for third-party SDKs) • Hide user defined classes (e.g.: instantiate them with methods) so Unity can’t see them • Wrap API calls with ones that use just primitive or built-in data type and the convert them to user defined classes inside plugin! ROME 24 June 2014 – Valerio Riva 18
  • 19. Run on UI Thread • iOS dispatch_async(dispatch_get_main_queue(), ^{ // Your code to run on the main queue/thread }); [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // Your code to run on the main queue/thread }]; • Android UnityPlayer.currentActivity.runOnUiThread(new Runnable() { public void run() { //your code to run on the UI thread } }); ROME 24 June 2014 – Valerio Riva 19
  • 20. Run on UI Thread (WP8) • MainPage.xaml.cs public partial class MainPage : PhoneApplicationPage { public void InvokeOnAppThread ( Action callback ) { UnityApp.BeginInvoke ( () => { callback (); } ); } public void InvokeOnUIThread ( Action callback ) { Dispatcher.BeginInvoke ( () => { callback (); } ); } private void Unity_Loaded() { … MyDispatcher.InvokeOnAppThread = InvokeOnAppThread; MyDispatcher.InvokeOnUIThread = InvokeOnUIThread; … } } • MyPlugin.cs MyDispatcher.InvokeOnAppThread(() => { //your Unity callbacks execution must be placed here }); MyDispatcher.InvokeOnUIThread(() => { //your code to run on UI Thread }); ROME 24 June 2014 – Valerio Riva 20
  • 21. Resources and examples Resources • http://docs.unity3d.com/Manual/Plugins.html • http://docs.unity3d.com/Manual/wp8-plugins.html • http://docs.unity3d.com/Manual/PluginsForAndroid.html • http://docs.unity3d.com/Manual/PluginsForIOS.html Examples • https://github.com/playgameservices/play-games-plugin-for-unity • https://github.com/googleads/googleads-mobile- plugins/tree/master/unity • https://github.com/guillermocalvo/admob-unity-plugin • https://github.com/mikito/unity-admob-plugin • https://github.com/bearprada/flurry-unity-plugin • https://github.com/mikito/unity-flurry-plugin • https://github.com/faizann/unity3d_flurry ROME 24 June 2014 – Valerio Riva 21
  • 22. Thank you! ROME 24 June 2014 – Valerio Riva 22 Question Time No animals were harmed in the making of this talk valerio.riva@gmail.com @ValerioRiva http://it.linkedin.com/in/valerioriva/

×