ページへ戻る

− Links

 印刷 

iOSでのANEの作成​/iOS側の作成 のソース :: NJF Wiki

xpwiki:iOSでのANEの作成/iOS側の作成のソース

« Prev[3]  
[[iOSでのANEの作成]]に戻る

ANEを作成するためには、iOS側のプログラムをまとめたスタティックライブラリ(.aファイル)が必要となります。その制作方法やテストの仕方をこちらでご紹介します。

この記事で使用しているXcodeのバージョンは9.2です。

*プロジェクトの作成 [#kc36aff3]

まずXcodeでテスト用にiOS端末上で実行するためのプロジェクトを作成します。
具体的には、ボタンを押すとアラート画面が表示されるアプリです。

まずXcode起動後にメニューからFile->New->Projectと選び、iOSタブから「Single View App」を選択します。

&ref(newProject.jpg,mw:480,mh:360);クリックで拡大

プロジェクト名などを指定します。ここでは「AneAlertSample」としています。Langageは「Objective-C」です。他の言語でもANEが作れるかも知れませんが、資料が一番多いObjective-Cが一番無難です。Objective-C忘れた、という方はこちら「[[iOS/Objective-C/チートシート]]」をどうぞ。Teamの所には登録済みの開発者アカウントを入れておきましょう。

&ref(newProjectSetting.jpg,mw:480,mh:360);クリックで拡大

あとは適当な場所にプロジェクトを作成します。

プロジェクトが作成できたら、まずProjectの設定項目からInfoを選び、Deployment Targetを「8.0」などの低いバージョンに設定します。

&ref(projectInfo.jpg,mw:480,mh:360); クリックで拡大

これを行わず、最新のバージョンを指定したままだと、64bitのライブラリしか作成されなくなります。しかしAir SDKによるANE作成は現在(ver.28)のところ、64bitと32bitの両方が含まれているユニバーサルなライブラリにしか対応していません。そのため、64bitしか対応していない最新のバージョンではANE作成時にエラーが発生します。忘れずにターゲットに古いバージョンを指定するようにしてください。

次に「Build Settings」で「All」タブを選び、「Architectures」の各項目を設定します。

&ref(BuildSettings.jpg,mw:480,mh:360);クリックして拡大。

特に「Build Active Architectures Only」を「No」にする事を忘れないでください。これが「Yes」のままだと、テスト中のデバイスのArchitectureしか有効にならないので、64bitのみのライブラリがビルドされたりといったことがおこり、前述のユニバーサルなライブラリの問題が発生することがあります。

他の項目は基本的にデフォルト値のままで大丈夫です。

*テスト用ボタンの配置 [#q4eb0dfa]

ANEの作成はけっこう面倒です。それを何度もやらなくてすむように、iOS上でテストはできるだけ行ってから、ANEの作成にうつった方が効率的です。そのためのテスト用ボタンを設置します。

Xcodeでプロジェクトを作成すると、デフォルトでは「Safe area」というレイアウトを利用しています。しかし、Build TargetをiOS8にしていると、「Safe area」はiOS9からなので、エラーが発生します。プロジェクトを開いただけなら問題ないように見えますが、実行しようとしたり、「Main.storyboard」や「LaunchScreen.storyboard」を表示しようとすると以下のようなエラーが出ます。

&ref(safeAreaError.jpg,mw:480,mh:360);クリックして拡大

iOS9にすればこのエラーは防げます。

もしiOS8のままで開発するなら、特に「Safe area」は利用しないので削除します。

そのために、まず「Main.storyboard」の「Safe Area」を選択します。

&ref(safeArea.jpg,mw:480,mh:360);クリックして拡大

次にXcodeのウインドウの右上のボタンを、次にその下のタブの一番左をアクティブにして、右側に各種情報が出るレイアウトにします。

&ref(rightTop_0.jpg,mw:480,mh:360);

すると右端中段に「Interface Builder Document」という項目が現れるので、「Use Safe Area Layout Guides」というチェックボックスのチェックを外します。すると「Safe Area」がなくなり、エラーも消えます。

&ref(safeAreaCheck.jpg,mw:480,mh:360);クリックして拡大

「LaunchScreen.storyboard」の方も同様にして「Safe Area」を消してください。

次にテスト用のボタンを配置します。Xcode右下の部分の丸いアイコンのタブをクリックし、スクロールするとボタンがあります。

&ref(buttonTab.jpg,mw:480,mh:360);クリックして拡大

それを「Main.storyboard」のエディタにドラッグ&ドロップで配置します。
サイズもボタンの端をドラッグすると調整できます。
真ん中寄せなどをしない場合、アプリの表示は左上が基準になるので、画面の右や下の方は表示が切れることがあります。
そのため、ボタンは左上の方に配置すると便利です。

&ref(buttonLocate.jpg,mw:480,mh:360);

テスト用なので、レイアウトや表示にこだわっても仕方がありませんが、さすがにラベルは変えられるようになっていないと、複数ボタン配置してテストするときに不便なので変えておきます。
エディタ上のボタンを選択状態にして、右上端のくさび形のアイコンのタブを選択し、「Title」のテキストを変更すれば、ラベルが変更されます。

&ref(buttonLabel.jpg,mw:480,mh:360);

次にボタンを押したときの処理を定義します。
Xcodeのウインドウの右上にある丸いボタンを押して、StoryboardとViewController.mを両方表示します。
ViewController.mが表示されない場合は、エディタ上の「< >」とか書いてある右側の部分をクリックしてManualにしてViewController.mを選択したり「< >」をクリックしたりすると切り替わります。

&ref(twoEditorBtn.jpg,mw:480,mh:360);

そして、ボタンをViewController.mの「@end」の上あたりにでも右クリックまたはコントロール+クリックでドラッグ&ドロップします。
すると以下のようなアクションの定義ウインドウが出ます。

&ref(actonDef.jpg,mw:480,mh:360);

Nameを「alertShowUp」とすると、その名前のメソッドがドラッグ&ドロップした場所に自動で挿入されます。
このメソッドがボタンが押されたとき(正確には押して離したとき)に呼び出されます。
たまに「Could not insert なんとか」というエラーが出るときがありますが、Xcodeのキャッシュの問題らしいです。Xcodeを再起動するとうまくいったりします。

動作確認のために、このメソッドにログ出力の処理を追加します。

 - (IBAction)alertShowUp:(id)sender {
     NSLog(@"alertShowUp");
 }

これで実行してボタンを押すと

 2018-01-05 21:49:46.619087+0900 AneAlertSample[30385:2700813] alertShowUp

などとXcodeの下部のログ表示部分に出力されれば、テスト用のボタンの配置は終わりです。

*ANE用のライブラリの作成 [#f803ea57]
このページの目的は作成したボタンを押すとアラート画面が表示されるようなテスト用アプリを作り、かつANE用のライブラリを作ることです。
このままこのテスト用アプリのプロジェクトに処理を書くこともできますが、そうするとあとでライブラリ製作用のプロジェクトを作って内容をコピーしなくてはいけなくなるため、面倒です。
はじめからライブラリ用のプロジェクトを制作し、それを先ほど制作したテスト用のプロジェクトにリンクさせた方が簡単です。
そのためにここでライブラリ用のプロジェクトを制作します。

まずXcode起動後にメニューからFile->New->Projectと選び、iOSタブから「Cocoa Touch Static Library」を選択します。

&ref(cctStaticLibrary.jpg,mw:480,mh:360);

この後のプロジェクトの作り方は「[[プロジェクトの作成>#kc36aff3]]」と全く同じなので、そちらを参考にしてください。ここではプロジェクトの名前は「anealert」としました。

また、ターゲットのバージョンや「Build Settings」なども「[[プロジェクトの作成>#kc36aff3]]」と同じように設定してください。

ちなみにライブラリプロジェクトをそのままビルドした場合はライブラリプロジェクトの設定が、ライブラリプロジェクトを他のプロジェクトにリンクさせた場合は親になっているプロジェクトの設定が適用されます。
混乱しないように、両方同じにしておくのが無難です。

ライブラリプロジェクトが作成できたら、一度Xcodeを終了させます。

再びXcodeを開き、ライブラリプロジェクトを参照する親プロジェクトであるAneAlertSampleを開きます。
開いたらライブラリプロジェクトanealertをAneAlertSampleのファイルが表示されている部分へドラッグ&ドロップします。

&ref(libraryDD.jpg,mw:480,mh:360);

するとライブラリプロジェクトが入れ子となって表示されるようになり、両方のプロジェクトのファイルが編集可能になります。

&ref(libLink.jpg,mw:480,mh:360);

ちなみに、Xcodeを再起動せず、ライブラリプロジェクトを開いたまま上の手順を行うと、「すでにプロジェクトが開いています」といった内容のエラーが発生し、ビルドも何もできない状態になります。そうなったらXcodeを一度再起動し、ライブラリプロジェクトは開かずに親となっているプロジェクトを開いてください。

最後にライブラリをリンクさせるため、親プロジェクトであるAneAlertSampleのTARGETSのAneAlertSampleの「Linked Frameworks and Libraries」にlibanealert.aを加えます。

&ref(libLinkTarget.jpg,mw:480,mh:360);クリックして拡大

そして、ヘッダーファイルが参照できるように、同じく親プロジェクトであるAneAlertSampleのTARGETSのAneAlertSampleの「Build Settings」の「User Header Search Paths」にライブラリプロジェクトであるanealertのヘッダーファイルがある場所を指定します。ダブルクリックして「+」ボタンを押した後ヘッダーファイルが入ったフォルダをドラッグ&ドロップすればフルパスが入るので便利です。

&ref(libHeader.jpg,mw:480,mh:360);

これで、ライブラリ開発とそれを使ったテスト用アプリの開発が一度にできるようになります。

ただし、まれにビルドしようとしたときにライブラリプロジェクトのエラーが表示されず「Build Faild」とだけ表示されることがあります。その場合は一度Xcodeを閉じ、ライブラリプロジェクトのみを開いてビルドし直せば、エラーの場所が表示されます。

*主処理の追加とアプリとしてのテスト [#n6d6c2ec]

ライブラリの中心となるアラート表示の部分と、テスト用にそれを呼び出すボタンの処理を作成します。

まず、アラートを表示する「anealert.m」の処理は以下の通りです。

 #import "anealert.h"
 @interface AneAlert()
 - (void)onYesButtonPressed;
 @end
 @implementation AneAlert
 - (void) alertWindowInit{
     if(alertController == nil){
         NSLog(@"alertWindowInit");
 
         alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
         
         // Yes button
         [alertController addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
             [self onYesButtonPressed];
         }]];
     }
     
 }
 - (void) alertWindowShow:(NSString*)title : (NSString*)message{
     NSLog(@"alertWindowShow");
     id delegate = [[UIApplication sharedApplication] delegate];
     UIWindow * win = [delegate window];
     alertController.title = title;
     alertController.message = message;
     [win.rootViewController presentViewController:alertController animated:YES completion:nil];
 }
 - (void)onYesButtonPressed {
     NSLog(@"onOtherButtonPressed");
 }
 @end

これに対応するanealert.hは以下の通りです。
 #import <UIKit/UIKit.h>
 
 @interface AneAlert : NSObject{
 @private
     UIAlertController *alertController;
     UIViewController *viewController;
 }
 - (void) alertWindowInit;
 - (void) alertWindowShow:(NSString*)title : (NSString*)message;
 
 @end

基本的に通常のObjective-Cでのアラート表示の処理ですが、viewControllerの取得方法には注意が必要です。
つい、AneAlertSampleプロジェクトの中のViewControllerを使いたくなりますが、これはテスト用のクラスであり、ANEとして実行するときには存在しません。そのため、少し面倒でも、上記alertWindowShowメソッド中で行っているように、UIApplication sharedApplicationからUIWindowを参照し、そこからrootViewControllerを引き出す必要があります。
この方法は画面表示を伴うANEの作成では必須と言えるほどよく使うので、おぼえておいた方が良いでしょう。

これを呼び出すViewController.mの処理は、前述のボタンの処理を以下のように書きかえます。

 - (IBAction)alertShowUp:(id)sender {
     NSLog(@"alertShowUp");
     if(aneAlert == nil){
         aneAlert =  [[AneAlert alloc] init];
         [aneAlert alertWindowInit];
         cnt = 1;
     }
     NSString *message = [NSString stringWithFormat:@"%d times.", cnt];
     [aneAlert alertWindowShow:@"Ane Test from objective-C" : message];
     cnt++;
     
 }

また、ここで使う変数の定義も行います。
 #import "ViewController.h"
 #import "anealert.h"
 @interface ViewController (){
     AneAlert *aneAlert;
     int cnt;
 }
 
 @end

これで実行すると、ボタンを押すたびにメッセ時の数字が変わるアラートが表示されます。

&ref(sciOS.jpg,mw:480,mh:360);

このように、ANEの作成では一度テスト用のアプリを作って実行してみるのがお勧めです。
そうではなく、いきなりANEとして作成してAirで動かそうとするとエラーが起きたときにデバッグがとても大変です。

*ANE呼び出し処理の追加 [#r244033a]

いよいよANEの呼び出し部分を作成します。この部分でエラーが起こるとソースを変更するたびにいちいちANE作り替えなければならずデバッグが面倒なので、できるだけシンプルにするように心がけてください。

まず、「Air SDK」のincludeフォルダの中にあるFlashRuntimeExtensions.hをライブラリプロジェクトへとドラッグ&ドロップドロップします。

&ref(flashrantimehDD.jpg,mw:480,mh:360);

そしてコピーします。

&ref(flashrantimecopy.jpg,mw:480,mh:360);

次に呼び出しのための関数などを定義するファイルを作成します。
クラスなどを定義するわけではないので、Objective-Cの空ファイルを選びます。

&ref(newFile.jpg,mw:480,mh:360);

名前はAneAlertCall.mとしました。

&ref(newEmptyFile.jpg,mw:480,mh:360);

ANEの作成には実際のネイティブな処理を行う関数の他に、次の3つの関数があります。

+初期化関数
+コンテクストの初期化関数
+終了関数

このうち終了関数については、終了処理がないなら特に定義しなくてもかまいません。

この事を踏まえて、ANE呼び出し処理は以下のようになります。

 #import <Foundation/Foundation.h>
 #import "FlashRuntimeExtensions.h"
 #import "anealert.h"
 
 AneAlert * aneAlert;
 
 FREObject ANEAlertShow(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
     NSLog(@"ANEAlertShow start");
     uint32_t argLength; //引数の長さ
     const uint8_t *argBuff; //引数の値保持用
     
     FREGetObjectAsUTF8(argv[0], &argLength, &argBuff);//引数取得
     NSString *arg1NSString = [NSString stringWithUTF8String:(char*)argBuff];//引数をNSStringへ変換
 
     FREGetObjectAsUTF8(argv[1], &argLength, &argBuff);//引数取得
     NSString *arg2NSString = [NSString stringWithUTF8String:(char*)argBuff];//引数をNSStringへ変換
     
     if(aneAlert == nil){
         NSLog(@"ANEAlertShow:init alert!");
         aneAlert = [[AneAlert alloc] init];
         [aneAlert alertWindowInit];
     }
     [aneAlert alertWindowShow: arg1NSString : arg2NSString];
     NSLog(@"ANEAlertShow end");
     return NULL;
 }
 
 void ANEAlertContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
 {
     NSLog(@"ANEAlertContextInitializer start");
     
     *numFunctionsToTest = 1;
     
     FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * *numFunctionsToTest);
     
     func[0].name = (const uint8_t*) "alert";
     func[0].functionData = NULL;
     func[0].function = &ANEAlertShow;
     
     *functionsToSet = func;
     
     NSLog(@"ANEAlertContextInitializer end");
 }
 
 void ANEAlertInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet){
     NSLog(@"ANEAlertInitializer start");
     *extDataToSet = NULL;
     *ctxInitializerToSet = &ANEAlertContextInitializer;
     NSLog(@"ANEAlertInitializer end");
 }

ここでANEAlertInitializerが初期化処理です。この関数名はあとでANEの作成時に必要です。
ANEAlertContextInitializerは呼び出し関数を定義しています。
ここではANEAlertShow関数を「alert」という文字列で呼び出せるようにしています。
ANEAlertShowがアラート表示する関数です。ここで引数の取得方法が特殊なので注意していください。
FREGetObjectAsUTF8を使っていますが、UTF8以外にも型に合わせたいろいろな関数があります。
詳しくは公式ドキュメント「[[ネイティブ C API リファレンス ユーザー使用関数>https://help.adobe.com/ja_JP/air/extensions/WSb464b1207c184b14-62b8e11f12937b86be4-7ff9.html]]」を参照してください。

最後にAneAlertCall.mがちゃんとライブラリに含まれているか確認します。ライブラリプロジェクトのターゲット>anealert>「Build Phases」>「Compile Sources」にAneAlertCall.mがあればOKです。Xcodeのファイルの追加を使うとの通常自動で入っています。入っていなかったらここで加えてください。

&ref(aneAlertComileS.jpg,mw:480,mh:360);

*ライブラリファイル(.aファイル)の取り出し [#q2a8ceec]

ここで作成したライブラリを取り出します。
まず実機をUSBで接続し、左上のテスト用の端末をその実機とします。

&ref(targetIpod.jpg,mw:480,mh:360);

こうしないとシミュレーター用のバイナリが書き出されることがあるようです。

次にメニューのProductからBuildを選びます。
これでライブラリが作成されます。
少し余分に時間がかかりますが、場合によっては古いファイルが残らないように、念のためCleanしてからBuildした方が良いかも知れません。

&ref(buildClean.jpg,mw:480,mh:360);

Buildの時に以下のような警告がでますが気にしないでください。

&ref(FlashRuntimeExtensionCaution.jpg,mw:480,mh:360);

これはコメントの書き方のルールについてで、しかも場所はヘッダーファイルです。実際のライブラリにこの部分は含まれず問題ありません。

Buildが正常に終われば、左側のProductのところにあるライブラリを右クリックまたはCtrl+クリックします。
メニューが現れるので「Show in Finder」を選択すればファインダーでライブラリが参照できます。

もしライブラリがないと赤字で表示されるので、エラーを修正してください。

&ref(libane.jpg,mw:480,mh:360);

以上でライブラリの作成は終わりです。

[[iOSでのANEの作成/swcの作成]]に進む

[[iOSでのANEの作成]]に戻る

« Prev[3]