Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Unityネイティブプラグインマニアクス #denatechcon

7,754 views

Published on

DeNA TechCon 2017の登壇資料です。

Published in: Technology
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Unityネイティブプラグインマニアクス #denatechcon

  1. 1. Copyright (C) DeNA Co.,Ltd. All Rights Reserved.Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Unityネイティブプラグインマニアクス DeNA Technology Conference 2017 1 Japanリージョンゲーム事業本部 開発基盤部 Haruto Otake Sae Yamauchi
  2. 2. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 自己紹介  大竹 悠人(Otake Haruto) ⁃ 開発基盤部 第二グループ所属 ⁃ 来歴 • 2009年ドワンゴに新卒入社 ⁃ 幾つかのサービスや、家電/ゲーム機向けプロダクトを担当 • 2013年 DeNAに中途入社 ⁃ Webソーシャルゲームタイトルの運用ののち、新規ネイティブゲーム開発へ参加 ⁃ 基盤整備を得意としていたらいつのまにかそっちが本業に ⁃ 現在はUnityに関連した技術サポートと、様々な内製ライブラリの制作/保守に従事 2
  3. 3. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 自己紹介  山内 沙瑛 (Yamauchi Sae) ⁃ 開発基盤部 第三グループ所属 ⁃ 来歴 • 2012年 新卒入社 ⁃ 主に共通基盤の開発に携わる • UIテスト自動化 • ゲーム用SDKのメンテナンス • Unityの共通モジュール開発・メンテナンス及び調査 ⁃ ゲーム用BaaSのSDK / サーバーサイドの開発・運用を行っている 3
  4. 4. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. アジェンダ  ネイティブプラグインとは ⁃ なぜ必要なのか  ネイティブプラグインのつくりかた ⁃ ネイティブプラグインとしての実装 ⁃ 必要な実装 ⁃ 利用者向けフロントエンド実装  プラグイン作成時の注意点と対応策 ⁃ マルチプラットフォーム対応 ⁃ 安定性 ⁃ 実機上での実行効率  まとめ 4
  5. 5. Copyright (C) DeNA Co.,Ltd. All Rights Reserved.Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインとは 5
  6. 6. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインとは Unityの機能を拡張するための、ネイティブ実装ライブラリのこと。 ネイティブ実装とインターフェースを用意することで、相互に呼び出しできる。  参考 ⁃ Unity マニュアル ネイティブプラグイン https://docs.unity3d.com/ja/current/Manual/NativePlugins.html 6 ゲームコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース
  7. 7. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. なぜ必要なのか 大きく分けると以下の理由がある。  Unityが提供していないプラットフォームAPIを使用するため  ネイティブ実装された機能をUnityで使用するため 7
  8. 8. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. Unityが提供していないプラットフォームAPIを使用するため iOS Push通知や動画再生などはゲームコードから呼び出せる。 以下の様な機能のAPIを使用したい場合は、Unityが対応していないため、直接呼び 出すことができない。 そのため、ネイティブプラグインを作成する必要がある。  例 ⁃ WebView表示 ⁃ Android Push通知設定 ⁃ 空きディスク容量取得 8
  9. 9. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 技術資産を流用するため ネイティブ実装されたミドルウェアや機能をUnityで使用するため。  例 ⁃ 社内モジュール • ゲーム特化BaaS(Sakasho) • サウンドエンジン(DeAL) • リアルタイム通信サーバー(IRIS) • アセット転送 ⁃ OSS • WebPローダ • ファイルの暗号化・復号化 9
  10. 10. Copyright (C) DeNA Co.,Ltd. All Rights Reserved.Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインのつくりかた 10
  11. 11. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインとしての実装 (1) ネイティブ実装と、それを呼び出すためのインターフェースを用意することで、 相互に呼び出しを行うことができる。  マネージドコード ⁃ ゲームコード(C#)に当たる ⁃ monoでビルドした場合は、仮想マシン上で実行されるコード ⁃ IL2CPPでビルドした場合は、最終的にはネイティブコードになる  ネイティブコード(アンマネージドコード) ⁃ C / C++ / Java 等で記述されたコード 11 マネージドコード (C#) ネイティブコード (C / C++ / Java等) インターフェース
  12. 12. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインとしての実装 (2) 実装例 (Androidの場合) 12 int add(int x, int y) { return x + y; } // test.c int add(int x, int y); // test.h libnative.so // ゲームコード上での呼び出し(C#) int result = add(1, 2); // P/Invoke宣言(C#) [DllImport("native")] private static extern int add(int x, int y); マネージドコード (C#) ネイティブコード インターフェース
  13. 13. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 必要な実装 A. 【ネイティブ】拡張機能のコア実装 B. 【ネイティブ】マネージドコードから呼び出すためのインターフェース C. 【マネージド】ネイティブコードとの連携実装 D. 【マネージド】利用者向け呼び出しフロントエンド実装 13 マネージドコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース C D A B
  14. 14. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 必要な実装 A. 【ネイティブ】拡張機能のコア実装 B. 【ネイティブ】マネージドコードから呼び出すためのインターフェース C. 【マネージド】ネイティブコードとの連携実装 D. 【マネージド】利用者向け呼び出しフロントエンド実装 14 マネージドコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース C D A B
  15. 15. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 拡張機能のコア実装 / マネージドコードから呼び出すためのインターフェース  ネイティブコード ⁃ 拡張機能のコア実装 ⁃ ゲームエンジンを跨いで利用可能な技術資産にできる  インターフェース ⁃ マネージドコードから呼び出すためのインターフェース ⁃ C Linkageの関数として実装する • 例 test.cpp extern "C" int hoge(); int hoge() { return 1; } 15 マネージドコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース C D A B
  16. 16. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 必要な実装 A. 【ネイティブ】拡張機能のコア実装 B. 【ネイティブ】マネージドコードから呼び出すためのインターフェース C. 【マネージド】ネイティブコードとの連携実装 D. 【マネージド】利用者向け呼び出しフロントエンド実装 16 マネージドコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース C D A B
  17. 17. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブコードとの連携実装 以下の機構でネイティブコードとマネージドコードの連携を行うことができる。  マネージドコード上 ⁃ P/Invoke • ネイティブコードをC#のメソッドのように呼び出すための機構 ⁃ AndroidJavaObjectなど(Androidのみ) • JNIを通じてAndroidのJavaのコードを呼び出す機構  ネイティブコード上 ⁃ UnitySendMessage • ネイティブからマネージドコードを呼び出すためのメソッド • 指定したGameObjectに文字列を送ることができる 17
  18. 18. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. P/Invoke (Platform Invoke) CLI(共通言語基盤)の機能で、ネイティブコードをマネージドコードの様に呼び出 すことができる。 引数や返り値は必要に応じて マーシャリング という変換処理が行われる。 18 ネイティブコード インターフェース P/Invoke宣言 マネージドコード(C#) マーシャラ 引数は System.String です 変換した データを用意しま す char*を 受け取りましたネイティブコード インターフェース P/Invoke宣言 マネージドコード(C#)引数は System.String です ???? [DllImport("ロード対象のプラグイン")] private static extern int add(int x, int y);
  19. 19. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. AndroidJavaObjectなど AndroidのAPIやJARに含まれるコードを呼び出すことができるUnityのAPI マネージドコードからクラス名を指定し呼び出すことができる。  参考: Unity マニュアル Android 用のプラグインをビルド ⁃ https://docs.unity3d.com/ja/current/Manual/PluginsForAndroid.html using (AndroidJavaClass cls = new AndroidJavaClass("java.util.Locale")) { using(AndroidJavaObject locale = cls.CallStatic<AndroidJavaObject>("getDefault")) { Debug.Log("current lang = " + locale.Call<string>("getDisplayLanguage")); } } 上記ドキュメントに記載されている呼び出し例(C#): 19
  20. 20. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. UnitySendMessage ネイティブコードからマネージドコードに文字列を渡すことができる。 指定したGameObjectの指定したメソッドに対して、stringを引数にして呼び出す。 ネイティブで一定処理を行った後に、結果を返したい場合などに使用する。  問題点 ⁃ 非同期のため、同一フレーム間でメッセージを受け取れるわけではない // GameObject名, メソッド名, 送信したい文字列 UnitySendMessage("GameObjectName", "MethodName", "Message to send"); 20
  21. 21. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 必要な実装 A. 【ネイティブ】拡張機能のコア実装 B. 【ネイティブ】マネージドコードから呼び出すためのインターフェース C. 【マネージド】ネイティブコードとの連携実装 D. 【マネージド】利用者向け呼び出しフロントエンド実装 21 マネージドコード (C#) ネイティブコード (例: OSSライブラリ) インターフェース C D A B
  22. 22. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 利用者向けフロントエンド実装 C Linkage関数のインターフェースをC#で扱いやすくするために、ラッパーを実装 する。  実装例 マネージドコード(C#) 22 public static class HogeBindings { [DllImport("hoge")] public static extern IntPtr create(int x); [DllImport("hoge")] public static extern void remove(IntPtr context); [DllImport("hoge")] public static extern int exec(IntPtr context, int x); } public class Hoge : IDisposable { private IntPtr context; public Hoge(int x) { context = HogeBindings.create(x); } public Dispose() { HogeBindings.remove(context); } public int Exec(int x) { return HogeBindings.exec(context, x); } }
  23. 23. Copyright (C) DeNA Co.,Ltd. All Rights Reserved.Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグイン作成時の注意点と対応策 23
  24. 24. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグイン作成時の注意点と対応策  マルチプラットフォーム対応 ⁃ 各プラットフォーム用のライブラリ対応 ⁃ 各プラットフォームごとのネイティブプラグイン呼び出し実装 ⁃ ネイティブプラグインのライフサイクル ⁃ ネイティブコードからマネージドコードを呼び出す実装の注意点  安定性 ⁃ フェイルセーフ性の担保 ⁃ アライメント問題の考慮  実機上での実行効率 ⁃ メモリコピーの回避 24
  25. 25. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 各プラットフォーム用のライブラリ対応 各プラットフォーム用(iOS / Android / macOS / Windows)に実装したライブラ リ を用意する必要がある。 Unity Editor上で動作させるため、macOSやWindows用のネイティブプラグイン も作成する。 プラットフォーム 形式 iOS Static Library (.a) Android Shared Library (.so) または JAR (JNI経由) macOS Loadable Bundle (.bundle) Windows Dynamic Link Library (.dll) 25
  26. 26. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 各プラットフォームごとのネイティブコードの呼び出し実装 (1) 各プラットフォーム用にP/Invoke宣言の対応も追加する。 ライブラリ毎にDllImport指定が異なるため、プリプロセッサディレクティブで分 岐させる。 加えて、IL2CPPビルドを使う場合は以下の対応も必要になる。  iOS / Android IL2CPP ⁃ Delegateを使ってネイティブコードからマネージドコードを呼び出す関数に MonoPInvokeCallback属性指定が必要 • 参考: https://docs.unity3d.com/ja/current/Manual/TroubleShootingIPhone.html  Android IL2CPP ⁃ ビルドエラーになるため、(iOS用の) DllImport("__Internal")宣言が有効に ならないようにする 26
  27. 27. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 各プラットフォームごとのネイティブコードの呼び出し実装 (2) #if UNITY_EDITOR // iOS, Android設定かつEditor上で実行した場合に対応するため最初の条件にしている [DllImport("nativeForEditor")] #elif UNITY_ANDROID [DllImport("native")] #elif UNITY_IOS [DllImport("__Internal")] #endif private static extern int add(int x, int y); プリプロセッサディレクティブ記述例 27
  28. 28. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインのライフサイクル (1) ネイティブプラグインのロードタイミングに注意する。  Android ⁃ ロード順序が担保されない • Android OSバージョンによっては、ライブラリの依存関係が解決されない ⁃ JNI_OnLoadが呼び出されない場合がある • JNI_OnLoad内で処理 (ライブラリをロードする等) を記述していると実行されない • 参考: https://fogbugz.unity3d.com/default.asp?737959_orv675eqjd2ro91g ライブラリは関数呼び出し時にロードされるため、ライブラリをロードするための 関数を用意し、依存関係順に呼び出しておく。 28
  29. 29. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグインのライフサイクル (2)  Unity Editor (macOS / Windows) ⁃ ネイティブプラグインがロードされるのは初回再生の初回呼び出し時のみ • ネイティブプラグインを更新した場合はUnityの再起動が必要 ⁃ Unity Editorの再生・停止モードには影響されない • 再生停止してもネイティブプラグインはアンロードされない ⁃ 初期化処理が複数回呼ばれうる処理にする • ゲームコードがリコンパイルされた後のアセンブリ置き換えで、終了処理が呼ばれな い場合がある • 何度初期化されても良いようにする。状態管理はネイティブプラグイン側で行う 29
  30. 30. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブコードからマネージドコードを呼び出す実装の注意点 (1) ネイティブプラグインからマネージドコードへ結果を返す場合に注意する。 ネイティブで作成したスレッドからマネージドコードを呼び出すと、 Unityの内部処理もネイティブプラグインからの呼び出しになる場合があり、問題 が起こる。  iOS / Androidアプリの場合 ⁃ Unityのメインスレッド前提の処理の一部で、例外が発生する事がある  Unity Editorの場合 ⁃ デバッガ接続を行うと、Unity Editorが応答不能になる 30
  31. 31. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブコードからマネージドコードを呼び出す実装の注意点 (2) ネイティブで作成したスレッドから、マネージドコードのコールバック処理 (Delegate等) は、直接呼び出さない。 Unityのメインスレッドから呼び出す。あくまでマネージド層からの処理として完 結させる。  対応例 ⁃ マネージド層でポーリングし、マネージド層からネイティブ層へ結果を問い合 わせる形にする (Pull型にする) 31
  32. 32. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブコードからマネージドコードを呼び出す実装の注意点 (3) 32 処理 スレッド作成 呼び出し 結果 処理 スレッド作成 呼び出し 結果 問い合わせ 結果 Unity メインスレッド ネイティブ実装 ネイティブで 作成したスレッド 返却 NG OK
  33. 33. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. ネイティブプラグイン作成時の注意点  マルチプラットフォーム対応 ⁃ 各プラットフォーム用のライブラリ対応 ⁃ 各プラットフォームごとのネイティブプラグイン呼び出し実装 ⁃ ネイティブプラグインのライフサイクル ⁃ ネイティブコードからマネージドコードを呼び出す実装  安定性 ⁃ フェイルセーフ性の担保 ⁃ プラットフォーム毎のアラインメント問題の考慮  実機上での実行効率 ⁃ メモリコピーの回避 33
  34. 34. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. フェイルセーフ性の担保 プレイヤーのユーザー体験を損ねないように。加えて、開発チームの開発効率を下 げないようにする。 すべてのネイティブコード呼び出しは常に安全に実行、正しく失敗する様にする。  例 ⁃ マネージドからエラーをハンドリングできる仕組み ⁃ ネイティブプラグインで発生したエラーもUnity Editor上から把握できるよう に 34
  35. 35. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. プラットフォーム毎のアラインメント問題の考慮 構造体を使用する場合、メモリ上の配置にアラインメントが発生する。 マーシャリング対象のため、アラインメントを意識し構造体を定義する。  8byteのフィールドは8の倍数の位置から配置される  その間はパディングとして未使用のフィールドになる struct Sample1 { int32_t field1; int16_t field2; int64_t field3; }; struct Sample2 { int32_t field1; int32_t field2; int64_t field3; }; sizeof(Sample1) // => 16 sizeof(Sample2) // => 16 35 field1 field2 field3 16bit 16bit 16bit 16bit 16bit 16bit 16bit 16bit field1 field2 field3 8byte int64_t(8byte)の前にint16_t(2byte)を定義した場合
  36. 36. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 実機上での実行効率 実行効率を上げるために、メモリコピーを回避する様にする。 そのためには、ネイティブ層とマネージド層のそれぞれのヒープを意識する必要が ある。  マネージドヒープ ⁃ マネージドコードから扱われるヒープ(CLIで管理される) • GCの処理で消されたり移動したりする可能性がある  ネイティブヒープ ⁃ ネイティブコードから扱われるヒープ 36
  37. 37. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (1) メモリコピーはマーシャリング時に発生する。 やり取りするデータが大きい・頻度が高い場合は、特にマーシャリングを回避する ようにする。 37 マーシャラ ネイティブコード マネージドコード (C#) ヒープ間のデータコピー 参照参照 マネージドヒープ ネイティブヒープ
  38. 38. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (2) 回避策として、Blittable型を使う方法がある。 Blittable型とはマネージド/ネイティブでメモリレイアウトが同じになる型のこと。 P/Invokeでマネージド/ネイティブへ受け渡す際に、マーシャリングせずに、参照 渡しができる。 (ただし、アドレスが保証されるのは関数呼び出しの間のみ) 38 マーシャラ ネイティブコード マネージドコード (C#) マネージドヒープを 直接参照する 参照 Blittable型の引数 マネージドヒープ ネイティブヒープ
  39. 39. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (3)  Blittable型の例 ⁃ bool, charを除くプリミティブな値型 (int/float/shortなど…) ⁃ Blittable型の一次元配列 ⁃ Blittableな型だけを含むStructLayout指定された値型 • ただしBlittable型の可変長配列を含む型は除く 39
  40. 40. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (4)  Blittable型の例 40 // bool, charを除くプリミティブな値型 int f1; // Blittable型の一次配列 int[] f2; // Blittable型だけを含むStructLayout指定された値型 [StructLayout(LayoutKind.Sequential)] unsafe struct S1 { int f1; fixed int[64] f2; // Blittable型の固定長配列は可 }
  41. 41. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (5)  非Blittable型の例 41 string f1; bool f2; struct S2 { int f1; } [StructLayout(LayoutKind.Sequential)] struct S1 { int[] f1; }
  42. 42. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (6) Blittable型にOut方向属性を指定すると、マネージドヒープの内容を直接読み込め るだけでなく、書き込みを行うことができる。 42 マーシャラ ネイティブコード マネージドコード (C#) マネージドヒープへ 直接書き込む 参照 Out属性付きBlittable型引数 マネージドヒープ ネイティブヒープ
  43. 43. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (7) P/Invoke及びマーシャリング方向属性を指定する例 extern "C" { void sample_encode(uint8_t* source, uint8_t * dest, int32_t count); } ネイティブコード (libsample.so, libsample.a) public class SamplePlugin { #if UNITY_ANDROID [DllImport("sample")] #elif UNITY_IOS [DllImport("__Internal")] #endif public static extern void sample_encode([In] byte[] source, [Out] byte[] dest, int count); } マネージドコード (C#) 43
  44. 44. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (8) Blittable型を使った参照では、アドレスが保証されるのは、関数呼び出し間のみの ため、同期呼び出しにしか使用できない。 ネイティブ層で非同期に処理を行いたい場合 (データのパースや復号化処理など) は、GCHandleを使用する。  GCHandle ⁃ 指定したインスタンスのガベージコレクタのハンドルを取得する機構 ⁃ マネージドヒープに置かれたインスタンスは、GCによってアドレスが移動す る可能性があるが、GCHandleを使うと固定することができる GCHandleで固定したインスタンスのポインタをネイティブ層に渡すことで、 ネイティブ層から、非同期で読み込み・書き込みを行うことができるようになる。 44
  45. 45. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (9)  GCHandleを使いマネージドヒープ書き込みを行う例 ⁃ (Androidネイティブプラグインとして実装した場合) 45 uint8_t *buffer_ptr; int32_t buffer_size; void set_buffer(uint8_t *buffer, int32_t size) { buffer_ptr = buffer; buffer_size = size; } void write() { // マネージドヒープへの書き込み memset(buffer_ptr, 0, buffer_size); int num[] = {0, 1, 2}; memcpy(buffer_ptr, num, sizeof(int) * 3); } ネイティブコード (libnative.so)
  46. 46. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. メモリコピーの回避 (10) 46 [DllImport("native")] private static extern void set_buffer(byte[] buffer, int size); [DllImport("native")] private static extern void write(); private byte[] bytes = new byte[100]; private GCHandle handle; // マネージド層のバッファのポインタをネイティブ層に渡す public void SetBuffer() { handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); set_buffer(bytes, bytes.Length); } // GCHandleで確保したバッファのため、後の呼び出し時でも書き込める public void OnLoadFinished() { write(); } public void Dispose() { handle.Free(); } マネージドコード (C#)
  47. 47. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. 出典  プラットフォーム呼び出しによるデータのマーシャリング ⁃ https://msdn.microsoft.com/ja-jp/library/fzhhdwae(v=vs.110).aspx  既定のマーシャリングの動作 ⁃ https://msdn.microsoft.com/ja-jp/library/zah6xy75(v=vs.110).aspx 47
  48. 48. Copyright (C) DeNA Co.,Ltd. All Rights Reserved. まとめ  ネイティブプラグインを作成することで、ゲーム用の機能や開発効率向上のため の機能を拡張することができるようになります。  ネイティブプラグインの実装には、各プラットフォームへの対応や、マネージド 層とアンマネージド層を意識した実装が必要です。 本発表がネイティブプラグイン開発に役立てば幸いです。 ご清聴ありがとうございました。 48

×