20210501のiOSに関する記事は5件です。

【Unity】iOSネイティブプラグイン開発を完全に理解する - Objective-C++について

本編「【Unity】iOSネイティブプラグイン開発を完全に理解する」の付録記事です。 記事中での用語や略称についてはそのまま本編に倣う形で記載していきます。 「Objective-Cは何となく聞いたことあるけど、Objective-C++は聞いたこと無い」「これらの違いは何?」と思う方も居るかもしれないので簡単に補足します。1 ざっくりと言ってしまうと「Objective-CとC++を混在させることが出来る言語」になります。 参考リンク Objective-C++ 取扱説明書 〜始め方から使い方、注意点まで〜【完全保存版】 Objective-C++ - Wikipedia Objective-Cとの違い ObjCはあくまで「C言語をベースに拡張した言語 (言語仕様的にはC言語の完全上位互換な言語)」であり、ObjCからは「C++の構文や機能、C++で書かれた既存のライブラリ」などを利用することが出来ません。 一方でObjC++の方は「C++の構文や機能、C++で書かれた既存のライブラリ」を利用することが可能となり、これによって「C++で書かれた既存のライブラリ」と言った資産を使い回すことができるようになります。2 導入方法 Xcode上から「ObjCのソースファイルの拡張子(.m)」を「ObjC++のソースファイルの拡張子(.mm)」に変換するだけで自動的にObjC++として認識されるようになります。 (Xcode上の○○Settingsをいじって〜的な操作は必要無く、本当にこれだけ) Unity上でも同様に、拡張子が.mmのソースファイルをAssets以下にインポートすると「ObjC++で書かれたネイティブプラグイン」として扱われるようになります。 P/InvokeでObjC++(.mm)のコードを呼び出すならextern "C"を指定して外部宣言する必要がある C#からP/Invokeで「拡張子が.mmのソースに実装されているObjC++のコード」を呼び出すなら、P/Invokeで呼び出される関数を外部宣言する際にextern "C"を指定する必要があります。 (言い方を変えるとC言語のリンケージを指定する必要がある) サンプルコードを載せておくと以下のようになります。 (この際には__cplusplusマクロも用いてC++コンパイラから読まれたときだけ有効にしている) Example.mm // MARK:- extern "C" (Cリンケージで宣言) #ifdef __cplusplus extern "C" { #endif // NOTE: この関数が実際にUnity(C#)から呼び出される int printHelloWorld() { return [Example printHelloWorld]; } #ifdef __cplusplus } #endif 逆にObjC(.m)ならextern "C"は不要 逆に「拡張子が.mのソースに実装されているObjCのコード」を呼び出すならこれを行う必要はなく、外部宣言時に以下のように実装することでC#からP/Invokeで呼び出せるようになります。 Example.m // NOTE: この関数が実際にUnity(C#)から呼び出される // 拡張子が`.m`のソースなら、これだけでC#から呼び出し可能 extern int printHelloWorld() { return [Example printHelloWorld]; } なぜObjC(.m)だと不要なのか? これらの理由について話すと、C++のコンパイラで「名前マングリング」と言う処理が行われているのが原因であり、C言語ベースのObjCだと名前マングリングが行われない為にextern "C"を付けなくても呼び出せるようになってます。 もっと具体的に「何が起こっているのか?」の詳細については以下の記事が参考になります。 C++のマングルとextern "C" { CとC++が混在したプログラムでの注意点 ちなみに自分はネイティブプラグイン開発時に初めてObjective-C++の名前を知ってこの疑問を抱きました。 ↩ 現にObjC++の用途の一つとして、「C++のライブラリをObjCからアクセスする為のラッパー記述」などが挙げられます ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】iPhoneのStatusBarを白にする

はじめに iPhoneの上部に表示されているステータスバー(Wifiや時間が表示されているところ)の色をアプリ全体で変更する方法を書きます。 実装方法 Project → Targets → Deployment Info → Status Bar Style Light Contentに変更します。 Info.plistにView controller-based status bar appearanceを追加します。 以上でStatusBarを白に変更することができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】iOSネイティブプラグイン開発を完全に理解する - Xcodeの設定を自動化する

本編「【Unity】iOSネイティブプラグイン開発を完全に理解する」の付録記事です。 記事中での用語や略称についてはそのまま本編に倣う形で記載していきます。 Unityのビルド結果にあるプロジェクトファイル(.xcodeproj)を開き、Xcode上でターゲット1を選択してからBuild Settingsを開けば名前の通りにアプリケーションのビルドに関する設定を行えます。 例えば以下のスクリーンショットでは例として「Swiftのバージョン指定」を選択してます。 こちらの設定はXcode上から手動で変更する以外にも、Unity上からビルド毎に自動で設定を変更することも可能であり、今回はそのやり方について解説していきます。 ※ 前提としてUnityの場合には手動で変える運用はオススメできない 設定項目の変更状態はXcodeのプロジェクトファイル(.xcodeproj)に紐付かれることになりますが、Unityと言ったプロジェクトファイルを自動生成する様な環境だと、例えばReplace相応のビルドを行った際にはビルド設定が適用された.xcodeprojも消えてしまうため、都度手動で再設定を行う必要が出てきます。 手動設定は運用を踏まえると、ビルドの自動化との相性問題もあれば、そもそもヒューマンエラーに繋がる懸念も出てきます。 ※逆にビルドエラー解決などの為に「一瞬手動で変えてみて試す」と言ったのは全然有りだと思います。ただ、最終的にはUnity上から自動で設定を適用するようにした方が良いかもです。 [PostProcessBuild]を利用して設定を自動化 Unityからプロジェクトファイルにある設定を書き換えるには、PostProcessBuildAttributeと言う属性を利用したEditor拡張を実装します。 こちらを利用するとビルドが完了したタイミングで属性を付けたメソッドを呼び出すことが出来るようになるため、ビルド完了後にXcodeプロジェクトファイルにアクセスして内容を書き換えると言ったアプローチを取ることが出来るようになります。 XcodePostProcess.cs #if UNITY_IOS using System.IO; using UnityEditor; using UnityEditor.Callbacks; using UnityEditor.iOS.Xcode; namespace MinimumExample.Editor { static class XcodePostProcess { /// <summary> /// ビルド完了後に呼び出される /// </summary> /// <param name="target">ビルドターゲット</param> /// <param name="path">ビルド結果のパス</param> [PostProcessBuild] static void OnPostProcessBuild(BuildTarget target, string path) { // ビルドターゲットがiOSなら処理 if (target != BuildTarget.iOS) return; // TODO: ここでビルド結果に対して手を加えることが出来る } } } #endif PBXProjectを利用してXcodeのプロジェクトファイルを書き換える Unityからプロジェクトファイルの内容を書き換えるにはPBXProjectと言うiOS(と言うよりはXcode)向けのAPIを利用します。 簡単な例として「Swiftバージョンを5.0に設定する」例を取り上げつつ、以下の要点について順に解説していきます。 A. ビルド結果のパスからPBXProjectを読み込んで、終わったら変更結果で上書き B. 設定を適用するターゲットのGUIDを取得 C. 設定変更の適用 XcodePostProcess.cs /// <summary> /// Swiftを実装するにあたって必要な設定を自動で適用する /// </summary> /// <param name="target">ビルドターゲット</param> /// <param name="path">ビルド結果のパス</param> [PostProcessBuild] static void OnPostProcessBuild(BuildTarget target, string path) { if (target != BuildTarget.iOS) return; // A. ビルド結果のパスからPBXProjectを読み込み var projectPath = PBXProject.GetPBXProjectPath(path); var project = new PBXProject(); project.ReadFromString(File.ReadAllText(projectPath));        // B. 設定を適用するターゲットのGUIDを取得 // 2019.3からは`UnityFramework`に分離しているので、targetGuidはこちらを指定する必要がある。 var targetGuid = project.GetUnityFrameworkTargetGuid(); // C. 設定変更の適用 (Swiftバージョンの設定) project.SetBuildProperty(targetGuid, "SWIFT_VERSION", "5.0"); // A. 変更結果で上書き File.WriteAllText(projectPath, project.WriteToString()); } 【補足】 そもそもPBXProjectとは? PBXProjectはXcodeプロジェクトファイルの中に含まれる設定ファイル的なものであり、主にプロジェクト内にあるファイルの定義/フォルダ階層構造/ビルド設定と言った要素を持ちます。 ビルド結果にある.xcodeprojを選択したら「右クリック -> パッケージの内容を表示」を選択することで、Finder上からアクセスすることが出来ます。(以下にあるproject.pbxprojが該当) [XXX.xcodeproj] L project.pbxproj L project.wxworkspace L [xcshareddata] ちなみにproject.pbxproj自体はテキスト形式なのでテキストエディタで開いて編集することも可能です。 ■ A. ビルド結果のパスからPBXProjectを読み込んで、終わったら変更結果で上書き PostProcessBuildから呼び出されるメソッドはパラメータとして「ビルド結果のパス」を受け取ることが出来るので、こちらをPBXProject.GetPBXProjectPathに渡すことで実際のPBXProjectのパスを取得します。 あとは取得したパスからPBXProjectを文字列として読み込み、それをReadFromStringに渡すことで初期化を完了させます。 XcodePostProcess.cs /// <param name="target">ビルドターゲット</param> /// <param name="path">ビルド結果のパス</param> [PostProcessBuild] static void OnPostProcessBuild(BuildTarget target, string path) { if (target != BuildTarget.iOS) return; // A. ビルド結果のパスからPBXProjectを読み込み var projectPath = PBXProject.GetPBXProjectPath(path); var project = new PBXProject(); project.ReadFromString(File.ReadAllText(projectPath)); そして後述する諸々の設定の適用が完了したら、上記で取得したPBXProjectのパスに対して結果を書き込みます。 (先行して書いてますが、これ自体は一番最後のプロセスになります) XcodePostProcess.cs // A. 変更結果で上書き File.WriteAllText(projectPath, project.WriteToString()); ※この例ではReadFromStringとWriteToStringで読み書きしましたが、他にも関連するAPIとしては以下のようなものが存在します。 PBXProject.ReadFromStream PBXProject.WriteToStream PBXProject.ReadFromFile PBXProject.WriteToFile ■ B. 設定を適用するターゲットのGUIDを取得 Unity2019.3以降からはPBXProject.GetUnityFrameworkTargetGuidを実行してUnityFrameworkと言うターゲットのGUIDを持っておきます。 GUIDの用途については後述します。 XcodePostProcess.cs // B. 設定を適用するターゲットのGUIDを取得 // 2019.3からは`UnityFramework`に分離しているので、targetGuidはこちらを指定する必要がある。 var targetGuid = project.GetUnityFrameworkTargetGuid(); 【補足】 そもそも"ターゲット"とは? ターゲットとはXcodeプロジェクトにある「ビルド設定のまとまり」みたいなものであり、それぞれが独自の設定項目(アプリ名/ビルド設定/Bundle Identifier)などを持ちます。 Unityの場合には予め必要なものが設定されており、Xcodeの画面で言うと以下の①を選択したら表示される②の項目がターゲットになります。 2019.3からはアプリ本体側の機能がUnityFrameworkに集約されているので、PBXProject.GetUnityFrameworkTargetGuidからこのUnityFrameworkのGUIDを取得する必要があります。 もっと具体的に「それぞれのターゲットに何がどう含まれているのか?」については以下の公式ドキュメントのProject Targetsを御覧ください。 Structure of a Unity Xcode Project 【補足】 Unity2019.3前後ではプラグインに関する設定が変わってくるので注意 Unity 2019.3から新機能として「Unity as a Library」が入った影響で、iOS向けビルド後のXcodeプロジェクトファイル(.xcodeproj)の構成に大きく変更が掛かりました。 この記事中では2019.4をターゲットとしているので、基本的には2019.3以降の書き方で解説をしてますが、2018系統などを利用する場合にはこれらの設定が変わってくることについては念頭に置いておく必要があります。 詳細は以下の記事にて纏めているので、こちらを御覧ください。 【Unity】iOSネイティブプラグインをSwiftで実装する際には、2019.3前後で設定方法が変わる ■ C. 設定変更の適用 残るは設定変更の適用です。 今回の題材である「Swiftバージョンを5.0に設定する」の場合には、PBXProject.SetBuildPropertyを利用します。 第一引数にはターゲットのGUIDを指定 → B.の項目で取得したUnityFrameworkのGUIDを指定します 第二引数にはビルドプロパティの名前を指定 第三引数にはプロパティに設定したい値を指定 → 次で詳細に触れます XcodePostProcess.cs // C. 設定変更の適用 (Swiftバージョンの設定) project.SetBuildProperty(targetGuid, "SWIFT_VERSION", "5.0"); ビルドプロパティの名前について ここで指定するプロパティ名はXcode上から確認することが出来ます。 先ずはTARGETSからUnityFrameworkを選択し、[Build Settings]を開いたら設定したい項目を選択します。 (今回で言うとSwift Language Version) 選択したら以下のスクリーンショットの右上辺りにある①を選択してQuick Helpを表示し、②に記載されている文字列をUnity側で指定します。 → この例で言うとSWUFT_VERSIONが該当する文字列 他にもXcode Build Settingsと言うサイトには一通りのビルドプロパティや初期値、中には簡単な解説が記載されているので覚えておくと便利です。 Xcode Build Settings プロパティに設定したい値について 引数に渡す値は文字列である必要があるために"5.0"を渡してます。 少し余談にはなりますが、もしValueに何を渡せばよいのか分からない場合には、プロジェクトファイルに含まれるproject.pbxprojをテキストエディタで開き、該当するビルドプロパティで検索してやることで設定値を割り出せたりします。 例えば"SWIFT_VERSION"で検索した場合には↓の様に5.0と言った値が設定されているので、Unity側で渡すパラメータもこちらに準拠させればOKです。 project.pbxproj buildSettings = { (省略) SWIFT_VERSION = 5.0; (省略) }; その他設定項目 Swiftのバージョン指定を例にビルド設定の変更方法について解説してきましたが、他にも以下のような項目も設定可能です。 Frameworkの追加 Info.plistの設定 これらの設定例については以下のサイトが参考になります。 UnityでXcodeの設定を自動化する方法まとめ 設定の競合に注意 [PostProcessBuild]を利用した設定の自動化ですが、こちらの処理自体はプロジェクト中に複数実装することが出来ます。 もし複数箇所にてPBXProjectの書き換えを行った場合には、随時呼び出し順に従って設定が書き換えられていく事になりますが...注意しないと同一設定の書き換えが発生して競合するなんてことが起こり得ます。 同一設定は後から書き換えられたほうが優先される 例えば以下のXcodePostProcess1.csとXcodePostProcess2.csと言うソースがあったとして、先に呼び出される想定のXcodePostProcess1.csでは「SWIFT_VERSIONを5.0」に書き換えるとします。 そして次に呼び出される想定のXcodePostProcess2.csにて「SWIFT_VERSIONを4.0」に書き換えたとしたら、最終的なビルド結果は「SWIFT_VERSION : 4.0」が適用されることになります。 XcodePostProcess1.cs (クリックで展開) XcodePostProcess1.cs // NOTE: 属性の引数に呼び出し順を指定可能 [PostProcessBuild(1)] static void OnPostProcessBuild(BuildTarget target, string path) { if (target != BuildTarget.iOS) return; var projectPath = PBXProject.GetPBXProjectPath(path); var project = new PBXProject(); project.ReadFromString(File.ReadAllText(projectPath)); var targetGuid = project.GetUnityFrameworkTargetGuid(); // SWIFT_VERSIONを`5.0`に書き換え project.SetBuildProperty(targetGuid, "SWIFT_VERSION", "5.0"); File.WriteAllText(projectPath, project.WriteToString()); } XcodePostProcess2.cs (クリックで展開) XcodePostProcess2.cs [PostProcessBuild(2)] static void OnPostProcessBuild(BuildTarget target, string path) { if (target != BuildTarget.iOS) return; var projectPath = PBXProject.GetPBXProjectPath(path); var project = new PBXProject(); project.ReadFromString(File.ReadAllText(projectPath)); var targetGuid = project.GetUnityFrameworkTargetGuid(); // SWIFT_VERSIONを`4.0`に書き換え project.SetBuildProperty(targetGuid, "SWIFT_VERSION", "4.0"); File.WriteAllText(projectPath, project.WriteToString()); } 汎用的なプラグインを実装する際には、書き換えに注意すること もし色んなプロジェクトで使える想定の汎用的なプラグインを実装するとしたら、上記のような性質があるのでPBXProjectの書き換えには注意する必要があります。 (「導入したプラグイン側で意図せずにPBXProjectを書き換えてしまった」、若しくは「導入先のプロジェクトで期待する設定が書き換えられてしまった」なんてことが起こり得るので) もしプラグインの都合でPBXProjectを書き換える必要性が出てきた場合には、README辺りに「PBXProjectのこの設定を書き換えます」 or 「導入するならPBXProjectのこの設定を書き換えてください」と明記するなりした方が良いかもしれません。 ターゲットについては後述します ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】iOSネイティブプラグイン開発を完全に理解する - ネイティブプラグインを実装するには

本編「【Unity】iOSネイティブプラグイン開発を完全に理解する」の付録記事です。 記事中での用語や略称についてはそのまま本編に倣う形で記載していきます。 ここでは私がネイティブプラグインを実装する際によくやる手法/補足について解説します。 あくまで一例として参考にして頂けると幸いです。 この記事の中では「Xcode上から普通にプロジェクトを作成して開発するiOS向けのアプリ」のことを便宜的にネイティブアプリとして表記していきます。 TL;DR iOS向けのネイティブプラグインを作るなら、新規でネイティブアプリ用のプロジェクトを立ち上げて、そこで開発/動作確認すると効率が良い 新規でネイティブアプリ用のプロジェクトを作る際にはUIKitベースがオススメ プラグイン向けに実装したネイティブコードの手直しはUnityのiOSビルド結果であるXcodeプロジェクト上からも可能 Symlink Unity librariesの設定の有無に注意 プラグインとして導入するネイティブコードは別ソースに分けた上で独立性を高く実装 Unityとネイティブアプリのどちらからでも呼び出しやすいように プラグインとして使うネイティブコードはネイティブアプリのプロジェクト上で実装したほうが効率が良い 最終的にUnityに組み込む物と言えども、プラグインとして使うネイティブコードはネイティブアプリのプロジェクト上で実装したほうが圧倒的に効率が良いです。 → Unityが一切関与しないので、「ビルドが通るかどうかのチェック」や「実機動作確認」を高速に行うことが可能。 具体的な流れとしては以下のようになります。 Xcode上から新規でネイティブアプリ用のプロジェクトを立ち上げる 1で立ち上げたプロジェクト上からプラグインとして使うネイティブコードを実装 + 実機動作確認 2が完成したらソースをUnity上にインポート 実装/動作確認用のネイティブアプリは簡単なもので良い ネイティブアプリのプロジェクト上で実装/動作確認を行うには、ある程度のネイティブアプリ開発に関する知見が必要となってきますが、先ずは「ボタンを1つ配置してそこからプラグインとして利用するネイティブコードの処理を呼び出す」と言った簡易的なものでも十分だと思います。 この記事中ではネイティブアプリ開発に関する初歩的なところまでは触れませんが、先ずは公式資料なり初心者向けの書籍/サイトなりを参照して「ボタンを一つ配置してそこから処理を呼び出す」ところまでをキャッチアップしてみることをオススメします。 【補足】 Storyboard or SwiftUI? Xcodeから新規プロジェクト作成時に出てくる以下の画面にて、Interfaceと言うドロップダウンを選択するとStoryboardかSwiftUIかのどちらかを選択する事になりますが、ここではStoryboardを選択することをオススメします。 このStoryboardと言うのはSwiftUIが登場する以前からある従来の形式であり、更にそれらを包括する従来のUIフレームワーク全般のことをUIKitと言うのですが、ザックリと言ってしまえば現時点のUnity iOSビルドで出力されるXcodeプロジェクトはその従来の形式(UIKit)が使われているので、UI周りに関するプラグインを書く際には都合が良くなります。 この点についてはサンプルプロジェクトの解説にて再度補足します。 Unityにインポートしたネイティブコードの手直しはビルド結果のXcodeプロジェクト上からも可能 Unityにインポートしたネイティブコードはビルド結果のXcodeプロジェクトにそのままの形で含まれます。 → 場所としてはLibraries以下にAssets以下のフォルダ構成そのままの形で入る。 (以下は本編中にあるMinimumExampleの例) なので、もしネイティブコードの手直しが必要になったり、決め打ちの値を調整したくなったときにはUnityのビルド結果にあるネイティブコードを直接書き換えることで効率よくビルド/実機での動作確認を行えると言ったテクニックがあります。 【補足】 Symlink Unity librariesについての補足 Build SettingsにあるSymlink Unity librariesを有効にしてビルドすると、ビルド結果のXcodeプロジェクトに含まれるネイティブコードはシンボリックリンクとなるために、Xcodeで編集した際にはAssets以下にあるコードにもそのまま変更が適用されることになります。 逆にこちらのチェックをオフにした際にはネイティブコードはコピーされたものが含まれるので、Xcodeで編集した際にはAssets以下にあるコードにもそのまま適用されないので注意する必要があります。 その他、Symlink Unity librariesの詳細については以下をご覧ください。 参考リンク iOS build settings → Symlink Unity librariesを参照 iOSのビルド設定の「Symlink Unity libraries」の意味 サンプルプロジェクト ここまでの流れに加え、幾つかの要点を補足するためのサンプルを用意しました。 内容としては「UnityのInputFieldから入力した文字列をネイティブのシェアUIを開いてシェアする」アプリとなります。 サンプルは「plugin-development-objc++」ブランチにて管理しており、以下2点のプロジェクトを含んでます。 Unityプロジェクト プラグイン開発用のネイティブアプリプロジェクト → XcodeProjects/PluginDevelopment-Example/PluginDevelopment-Example.xcodeproj サンプルアプリのイメージはこちら (クリックで展開) ネイティブアプリのサンプル ※ネイティブアプリ側はあくまで動作確認用なのでシェアUIに渡す文字列は固定です。 Unityのサンプル このサンプルのトピック このサンプルでは主に以下のトピックについて話していきます。 プラグインとして導入するネイティブコードは独立性を高くして実装 → Unity/ネイティブアプリの両方から呼び出しやすい設計に UIKitに関連するプラグインを実装する際の注意点 求める予備知識 あとはiOSネイティブアプリ開発周りの予備知識としては、以下の範囲まではキャッチアップ済みであるという事を前提に解説していきます。 Storyboard & Objective-Cベース1の新規プロジェクト作成 新規ソースの追加 Storyboard上にボタンを一つ配置して、押されたときの処理の呼び出しまで実装 ■ プラグインとして導入するネイティブコードは独立性を高くして実装 プラグインとして導入するネイティブコードは別ソースに分けた上で、独立性を高く実装しておくと取り回しがよくなります。 早い話「ネイティブアプリにベッタリ依存するような書き方は避けて剥がしやすくする」と言うイメージですが、具体例について次で解説していきます。 ※解説の対象となる該当ソース全体のリンクはこちら 2 NativeShare.mm NativeShare.h ■ Unity/ネイティブアプリの両方から呼び出しやすい設計に もう少し具体的な内容に踏み込むと、シェアUIの表示を行うNativeShareクラスは以下のような実装となっており、なるべくネイティブアプリの状態や呼び出し元のViewに依存しないような作りにしてあります。 今回主に依存性が発生しそうなポイントとしてはshareTextで呼び出されているUIActivityViewControllerであり、こちらを表示する際には自身のUIViewControllerを要求されますが、そちらを引数化することでUnity/ネイティブアプリの両方から呼び出しやすくしてます。 NativeShare.mm // MARK:- implementation (クラスの実装部) @implementation NativeShare + (void)shareText:(NSString*)text viewController:(UIViewController*)vc { // NOTE: UIActivityViewControllerでシェア // ref: https://developer.apple.com/documentation/uikit/uiactivityviewcontroller?language=objc NSArray* array = @[text]; UIActivityViewController* avc = [[UIActivityViewController alloc] initWithActivityItems:array applicationActivities:nil]; [vc presentViewController:avc animated:TRUE completion:nil]; } @end 具体的な呼び出し箇所の実装及びポイントとしては以下のようになります。 ネイティブアプリからの呼び出し ViewControllerからボタン押下時にネイティブプラグイン向けのクラスとして実装しているNativeShareのメソッドを直接呼び出すようにしてます。 ポイントとしては、C#から呼び出される想定のP/Invoke用の外部宣言関数はここでは呼び出しません。 ViewController上からの呼び出しとなるので、shareTextの第二引数にはそのままselfを渡してます。 XcodeProjects/PluginDevelopment-Example/PluginDevelopment-Example/ViewController.m // ボタン押下で呼び出される処理 - (void)tapButton:(UIButton*)button { // 渡す文字列 NSString* text = @"ネイティブアプリからの呼び出し"; // Unity向けのネイティブプラグインを呼び出し [NativeShare shareText:text viewController:self]; } ちなみに外部宣言関数の方は以下のように本来呼び出す想定のUnityGetGLViewController()をコメントアウトし、代わりにダミー変数を渡すことでコンパイルだけ通るような形にしてます。 意図についてはコメントに記載してますが、改めて後述します。 XcodeProjects/PluginDevelopment-Example/PluginDevelopment-Example/ViewController.m #ifdef __cplusplus extern "C" { #endif // NOTE: C#から渡される文字列はcharのポインタ型として渡される void shareText(char* textPtr) { // NSStringへの変換 NSString* text = [NSString stringWithCString:textPtr encoding:NSUTF8StringEncoding]; // NOTE: Unity上からViewControllerを取得するには`UnityGetGLViewController()`を使う // ※これ自体はUnityがiOSビルドで出力したプロジェクト上からじゃないと呼び出せないので、ここではコンパイルを通すために一時的にコメントアウト //UIViewController* vc = UnityGetGLViewController(); UIViewController* vc = nil; [NativeShare shareText:text viewController:vc]; } #ifdef __cplusplus } #endif 【補足】 ネイティブコードをUnityにインポートする際の変更点 上記のNativeShare一式をUnityに持っていく際にはそのままのインポートはせずに、事前に以下の変更を加えててからインポートしてます。 ヘッダーファイル(.h)をソースファイル(.mm)にマージ 必須ではないが、個人的にマージした方が1ソースで済むために管理しやすいからと言う理由でやっている P/Invokeで呼び出される外部宣言関数内にて、Unityが持つViewControllerを渡すようにする 詳細は次で解説 Unity側にインポートしたネイティブコード全体としては以下のようになります。 NativeShare.mm Unityからの呼び出し Unityからの呼び出しは今まで通りにP/Invoke経由となるので、外部宣言している関数から呼び出されます。 ポイントとしては、Unity上からViewControllerを取得するにはUnityGetGLViewController()を呼び出すことで取得することが出来ます。 このUnityGetGLViewController()はUnityがiOSビルドで出力するプロジェクト一式に含まれるUnityAppController.mmと言うソースコードにて外部宣言されているので、呼び出すにはUnityのiOSビルド結果であることが前提3となります。 → 上記のネイティブアプリ側でコメントアウトしているのはこの為であり、補足で記載している通り、ネイティブコードをUnityに持ってくる段階で変更を加えて呼び出せるようにします。 /Assets/PluginDevelopmentExample/Plugins/iOS/NativeShare.mm // NOTE: 実態はUnityがiOSビルドで出力するプロジェクト中に含まれる`UnityAppController.mm`と言うソースにある extern UIViewController* UnityGetGLViewController(); // MARK:- extern "C" (Cリンケージで宣言) #ifdef __cplusplus extern "C" { #endif // NOTE: C#から渡される文字列はcharのポインタ型として渡される void shareText(char* textPtr) { // NSStringへの変換 NSString* text = [NSString stringWithCString:textPtr encoding:NSUTF8StringEncoding]; // NOTE: Unity上からViewControllerを取得するには`UnityGetGLViewController()`を使う UIViewController* vc = UnityGetGLViewController(); [NativeShare shareText:text viewController:vc]; } #ifdef __cplusplus } #endif ■ UIKitに関連するプラグインを実装する際の注意点 今回例に出した「シェアUIの表示」と言った「UIに関する機能」を呼び出す際にはViewControllerを要求されることがあります。 以下の補足にて「新規でネイティブアプリのプロジェクトを立ち上げるならStoryboardを選択した方が良い」と書いた理由はこれであり、UnityがiOSビルドで出力するプロジェクトはUIKitベースとなるために、APIの親和性の観点から今はこちらを選択したほうが良いかと思います。4 【補足】 Storyboard or SwiftUI? ここまでのまとめ サンプルを例に幾つかの要点を補足してきましたが、あくまで実装の一例として参考にして頂くようお願いします。 (ここに記載している手法が絶対ではない) 例えば以下の項目に記載している「ヘッダーファイル(.h)をソースファイル(.mm)にマージ」と言う対応は必須ではありませんし、UnityGetGLViewControllerに関する変更はUIKitが関わっているからこその変更内容になります。 → 逆に言うとUIKitが関わらないシンプルなAPIの呼び出しレベルであればこういった対応はしなくても良いかも 【補足】 ネイティブコードをUnityにインポートする際の変更点 サンプルのネイティブアプリ側の言語がObjCなのは、ネイティブプラグインをObjCで実装する都合から合わせているだけです。ここらに関しては特に縛りはなく、「プラグインはObjCだけど、ネイティブアプリはSwiftベースで実装」みたいに実装しやすい方に合わせてもよいかと思います。 ↩ 外部クラスから呼び出される都合からNativeShareクラスはソースとヘッダーに分ける形で用意してます ↩ ネイティブコード側で同名/相応の関数を実装してやればコンパイルを通すことはできるかもしれないが、今回のサンプルではそこまではやっていない。 ↩ 一応はUIKitとSwiftUIを連携するためのAPIも存在するが、その分キャッチアップに必要な範囲が広がってしまうので、必要になるまでは必須科目ではないかな〜と思ってます ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

たった3日で手軽に始める高コスパSwift入門

私はMENTAでSwiftやNext.js(React)・Firebaseなどを中心にプログラミングを教えております。 そこで、初心者の方にいつもオススメしている市販の参考書を使った学習方法について紹介致します。 教材選び、これはとても難しい問題です。 良い教材があったとしても時間が経つと、内容が古くなり悪い教材になってしまう場合もあります。 また、どれが良い本かというのも初学者だからこそ判断がつきにくいと思います。 この記事では、書店で実際にいくつか比較した2冊のおすすめ書籍を紹介いします。 この記事だけではなく、常に情報が何月何日に書かれたものかかなり気にしてください。 鮮度が悪いジャンルでは1年以内が望ましく、2年で限界ぐらいで考えても良さそうです。 Swiftに関わらず「文法書と応用書」この2冊以上の組み合わせで勉強するのが良いと考えています。 そのあと、すぐに何かを作ってみるというステップを私はオススメしています。 文法書 とっつきやすさという点で、こちらの書籍をオススメします。 ※ 7-9章は応用でゲームを作る章なのでスキップしても良いかなと思います たった1日で基本が身に付く! Swift アプリ開発 超入門 応用書 たった2日でマスターできるiPhoneアプリ開発集中講座シリーズをオススメします。 SwiftUI対応 たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 12/iOS 14対応 たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 11 Swift 5対応 最新版は、Xcode12と書いてある前者です。 ただ、SwiftUIで書いてある点が悩みどころなんですね... 賛美両論あるところではあると思われますが SwiftUIは発展途上であるため いまSwiftUIに関する部分を初学でやるというのが 素直におすすめできないと考えております。 そのため、控えめに後者のXcode11版をオススメします。 ただし、古いので読み替えないといけない部分がある可能性があり そこは苦労する可能性があります。 でも教科書でハマってしまったら? その時はプログラミングの質問ができるMENTAで聞きましょう! 市販の参考書+ハマったらMENTA、これがおそらく高コスパを実現します。 こちらは、500円クーポンがもらえる招待リンクです。 私もこのサイトに登録しているので 「米本剛士」で検索して頂きご依頼いただければご対応可能です。 もちろん、他の方を探して頂くのでもいいと思います。 MENTAを上手く使ってあげてください。 教科書が終わったら? なにか作ってみましょう! 企画が思いつかなければ誰かに相談してみましょう。 こちらもMENTAが活用できますよ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む