SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Adobe Developer Connection(AD)

ネイティブプラグインを使ったPhoneGapの拡張~iOS編

原題:ネイティブプラグインでPhoneGapを拡張する(iOS)

  • X ポスト
  • このエントリーをはてなブックマークに追加

 この記事では、XcodeでiOSデバイスを対象とするPhoneGap(Apache Cordovaとも呼ばれます)アプリケーション用のネイティブプラグインを使用する方法について説明します(転載元:Adobe Developer Connection)。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 今回は、Xcodeを使って、iOSデバイスを対象とするPhoneGap(Apache Cordovaとも呼ばれます)アプリケーション用のネイティブプラグインを使用する方法について解説します。

 PhoneGapを初めて使用する場合、またはPhoneGapの基本事項をもう一度確認する必要がある場合は、続行する前に『XcodeとPhoneGapでiOSアプリケーションを開発する』をお読みください。

 「Cordova」および「PhoneGap」という用語は、この記事ではほぼ同じ意味で使用されます。いずれも、ネイティブにインストールされるモバイルアプリケーションをHTMLおよびJavaScriptで作成するための、オープンソースの同一のアプリケーションプラットフォームを指します。PhoneGapのコードベースは、Apache Software Foundationの下でCordovaという名前のオープンソースになりました。アドビでは、現在でもPhoneGapという名前で配布しています。詳しくは、Brian Lerouxのブログ『PhoneGap, Cordova, and what's in a name?』を参照してください。このブログによると「現時点で、唯一の相違点はダウンロードパッケージの名称であり、しばらくはこのままの状態が続く」とあります。

 PhoneGapでは、ネイティブにインストールされるモバイルアプリケーションのユーザーインターフェイスを、Webテクノロジーを利用して構築できるだけでなく、デバイスのネイティブ機能を操作するためのJavaScriptベースのAPIも用意されています。デフォルトでは、PhoneGapからデバイスのカメラ、加速度センサー、ファイルシステム、GPS位置情報、メディア再生などの機能にアクセスできます。ただし、一部のネイティブAPIについては、JavaScriptアプリケーション内で利用することはできません。PhoneGapでデフォルトの機能セット以上のことをしたい場合は、PhoneGapネイティブプラグインモデルを使用して、核となるPhoneGap APIの機能を拡張できます。

 デスクトップブラウザーのプラグインとは異なり、PhoneGapのネイティブプラグインでは、カスタムコードを組み込むことで、PhoneGapアプリケーションフレームワークの守備範囲を広げることができます。PhoneGapのネイティブプラグインを使用すると、ネイティブコードでまったく新しいカスタム機能を作成し、ネイティブからJavaScriptへのブリッジを介して、その機能をPhoneGapアプリケーションに公開できます。つまり、あらゆるネイティブライブラリまたはフレームワークをJavaScriptベースのPhoneGapアプリケーションで利用できるということです。

PhoneGapネイティブプラグインの構造を理解する

 PhoneGapネイティブプラグインの記述を始める前に、PhoneGapアプリケーションのコンテナによってJavaScriptベースのアプリケーションからオペレーティングシステムのネイティブ機能をどのように利用できるようになるのか、その仕組みを理解しましょう。

 すべてのCordova APIは、関連する2つの部分で構成されています。アプリケーションからアクセスできるJavaScriptベースのインターフェイスと、ネイティブコードで操作を実行するための対応するネイティブクラスです。通常、JavaScriptクラスとネイティブクラスのAPIは、相互に対応しているため、理解するのは簡単です。JavaScriptクラスは、Cordova.exec()関数を使用して、ネイティブコードを呼び出します。Cordova.execを呼び出すときに、ネイティブクラスの名前およびネイティブ関数名への参照に加え、結果ハンドラー関数、エラーハンドラー関数、ネイティブコードに渡されるパラメーターの配列を渡すことができます。JavaScriptからネイティブへの通信はCordovaが管理するため、デベロッパーはアプリケーションの作成に集中できます。

 PhoneGapネイティブプラグインについて詳しくは、Cordova wikiで提供されている、核となるAPIのソースコードを参照してください。PhoneGapのフレームワーク全体は、ここに掲載されているパラダイムに基づいて構築されています。

最初のプラグインを作成する

 最初のPhoneGapネイティブプラグインの作成を開始するには、『XcodeとPhoneGapでiOSアプリケーションを開発する』で説明されている手順に従って、新規PhoneGapプロジェクトを作成する必要があります。私のプロジェクトには「MyFirstPhoneGapNativePlugin」という名前を付けました。

JavaScriptクラス

 Hello Xcodeプロジェクトをセットアップしたら、ネイティブプラグイン用のJavaScriptインターフェイスを作成できます。ネイティブコードで提供されるロジックに対応するクラスと関数を作成する必要があります。wwwフォルダーの下に、以下のような単純なJavaScriptクラスが含まれるHelloPlugin.jsという名前のJavaScriptファイルを作成します。

var HelloPlugin = { 
    callNativeFunction: function (success, fail, resultType) { 
        return Cordova.exec( success, fail, 
                             "com.tricedesigns.HelloPlugin", 
                             "nativeFunction", 
                             [resultType]); 
                   }
};

 HelloPluginクラスにはcallNativeFunctionという名前の関数が1つあり、この関数は、成功のコールバック関数、失敗のコールバック関数、resultType文字列パラメーターを取ります。callNativeFunction関数で、Cordova.exec関数をラップし、実際のネイティブコードを呼び出します。このクラス内にはその他のJavaScriptはありませんが、必要に応じてここにJavaScriptコードを追加できます。

 Cordova.execが呼び出されるとき、5つのパラメーターが渡されます。

  • 成功のコールバック関数への参照(ネイティブコードレイヤーからの成功の応答時に呼び出される関数)
  • 失敗のコールバック関数(ネイティブレイヤーからの失敗の応答時に呼び出される関数)
  • ネイティブコードクラスへの文字列参照(後ほど詳しく説明します)
  • 呼び出される関数の名前への文字列参照
  • ネイティブコードに渡されるパラメーターの配列

 JavaScriptとネイティブコードレイヤー間でのコード実行は、同時進行ではありません。したがって、PhoneGapネイティブプラグインを開発するときには、コールバック関数と非同期のコーディング手法を用いる必要があります。

ネイティブクラス

 ネイティブコードレイヤーを作成するには、核となるCordova APIのCDVPluginクラスを拡張する新しいObjective-Cクラスを作成することから始めます。

  1. PhoneGapプロジェクト内でPluginsディレクトリを右クリックし、「New File(新規ファイル)」を選択します(図1を参照)。

     

    図1:新規ファイルの作成
    図1:新規ファイルの作成
  2. New File(新規ファイル)ウィザードで、Objective-Cクラスのテンプレートを選択し、「Next(次へ)」を選択します(図2を参照)。

     

    図2:Object-Cクラステンプレートの選択
    図2:Object-Cクラステンプレートの選択
  3. 新規クラス名として「HelloPlugin」と入力し、クラスをCDVPluginのサブクラスにします(図3を参照)。

     

    図3:クラス名の指定
    図3:クラス名の指定
     CDVPluginクラスは、Cordovaクラスで拡張する際に必ず元となる親クラスです。CDVPluginクラスには、PhoneGAP APIによるネイティブからJavaScriptへの通信に必要なロジックがすべてカプセル化されています。PhoneGap.exec関数によって、この新しいクラスでの関数の呼び出しが可能になります。CDVPluginクラスにはwriteJavascriptという名前の核となる関数があり、これによって、PhoneGapアプリケーションのWebビューでJavaScriptを呼び出すことができます。ネイティブからWeb JavaScript方向の通信はすべてwriteJavascript関数を使用して実行されます。
  4. 「Next(次へ)」をクリックします。
  5. 新規ファイルの場所を指定するよう要求されたら指定し(Xcodeプロジェクト内のPluginsディレクトリが望ましい)、「Finish(完了)」をクリックして続行します。PhoneGapプロジェクト内に新しいヘッダーファイル(.h)と実装ファイル(.m)が追加されています(図4を参照)。

     

    図4:新しいネイティブクラスのファイル
    図4:新しいネイティブクラスのファイル
  6. 次に、.hファイルでnativeFunction関数の識別子を追加します。次に例を示します。
    #import <Cordova/CDV.h>
    
    @interface HelloPlugin : CDVPlugin
    
    - (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;
    
    @end
    
     この定義には、JavaScriptレイヤーから受け取る引数のNSMutableArrayと、オプションのディクショナリ(マップ)という2種類のパラメーターがあります。この例では、引数の配列以外は気を配る必要はありません。ヘッダーファイルにはメソッドのシグネチャーのみが含まれています。.hファイルにはアプリケーションのロジックは一切含めません。
  7. クラスのシグネチャーを作成したら、.mファイルのnativeFunction関数のインスタンスにロジックを追加します。このネイティブプラグインのクラス内で使用されるObjective-C関数のサンプルを以下に示します。
    #import "HelloPlugin.h"
    
    @implementation HelloPlugin
    
    - (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { 
    
       //get the callback id
       NSString *callbackId = [arguments pop];
       
       NSLog(@"Hello, this is a native function called from PhoneGap/Cordova!");
       
       NSString *resultType = [arguments objectAtIndex:0];
       CDVPluginResult *result;
       
       if ( [resultType isEqualToString:@"success"] ) { 
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"Success :)"];
            [self writeJavascript:[result toSuccessCallbackString:callbackId]];
       }
       else {
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"Error :("];
             [self writeJavascript:[result toErrorCallbackString:callbackId]];
      }
    }
    
    @end
    
     nativeFunctionメソッド内で、まず、NSString callbackIdへの参照を取得する必要があります。これは、この関数の応答を呼び出し元のJavaScriptにマッピングするために、核となるPhoneGap APIで使用されます。

     次に、このメソッドは、NSLogを使用してXcodeデバッグコンソールへメッセージを記述します。ここで示されるのは、ネイティブコードを実行していることだけです。

     デバッグコンソールへの記述が終わると、関数に渡されたresultTypeを確認し、適切なCDVPluginResultインスタンスが作成されます。resultTypeの値は単純な文字列です。resultTypeが「success」の場合、「成功」の結果が作成され、[self writeJavascript]関数を使用して、JavaScriptレイヤーに対して成功のコールバックが記述されます。resultTypeパラメーターがそれ以外の値の場合、「失敗」の結果が生成され、JavaScriptレイヤーに対して失敗のコールバックが記述されます。

     JavaScriptで成功または失敗のコールバック関数を記述するときは、常にCDVPluginResultインスタンスを使用します。ただし、writeJavascript関数を使用してJavaScript文字列をJavaScriptレイヤーに返すこともできます。このテクニックは、ネイティブレイヤーからJavaScriptレイヤーにデータをリアルタイムにプッシュする場合にも利用できます。

プラグインを呼び出す

 プラグインが完成したら、PhoneGapアプリケーションから呼び出すことができます。

  1. まず、新しいプラグインのJavaScriptインターフェイスクラス(HelloPlugin.js)への参照を追加する必要があります。index.htmlファイルに新しい<script>タグを追加します。
    <script type="text/javascript" charset="utf-8" src="HelloPlugin.js"></script>
    
  2. また、onDeviceReady()関数の後に、ネイティブプラグインを呼び出してプラグインの結果を処理するためのJavaScriptを追加します。以下のように、callNativePlugin、nativePluginResultHandler、nativePluginErrorHandlerという名前のJavaScript関数を追加します。
    function callNativePlugin( returnSuccess ) {
        HelloPlugin.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess ); 
    }
    
    function nativePluginResultHandler (result) {
        alert("SUCCESS: \r\n"+result );
    }
    
    function nativePluginErrorHandler (error) {
        alert("ERROR: \r\n"+error );
    }
    
  3. callNativePluginは、単にネイティブプラグインクラスのJavaScriptインターフェイスを呼び出すための関数です。この関数がcallNativeFunctionメソッドを呼び出すときに、ネイティブコードレイヤーから受け取る成功および失敗ステータスのコールバック関数が渡されます。ネイティブコードレイヤーから成功のコールバックが返された場合は、nativePluginResultHandler関数が呼び出され、ネイティブコードレイヤーから失敗のコールバックが返された場合は、nativePluginErrorHandler関数が呼び出されます。
  4. 次に、下記のコードに示すように、プラグインを呼び出すJavaScriptボタンを2つ追加します。
    <body onload="onBodyLoad()">
        <h1>Hey, it's Cordova!</h1>
         
          <button onclick="callNativePlugin('success');">Click to invoke the Native Plugin with an SUCCESS!</button>
          <button onclick="callNativePlugin('error');">Click to invoke the Native Plugin with an ERROR!</button>
    </body>
    
     最初のボタンがクリックされると、callNativeFunctionメソッドが「success」のパラーメーターと共に呼び出されます。PhoneGapは次に、ネイティブコードを実行し、JavaScriptレイヤーで成功のコールバックを呼び出します(nativePluginResultHandler関数を呼び出します)。

     2番目のボタンをクリックすると、callNativeFunctionメソッドが「error」のパラーメーターと共に呼び出されます。PhoneGapは次に、ネイティブコードを実行し、JavaScriptレイヤーで失敗のコールバックを呼び出します(nativePluginErrorHandler関数を呼び出します)。

ネイティブコードクラスをマッピングする

 この時点でほぼすべての準備が完了していますが、JavaScriptからネイティブコードを呼び出せるようにするには、実行する手順がもう1つあります。

 Cordovaがネイティブコードクラスを識別できるように、マッピングを追加する必要があります。Cordova.execを呼び出すときにネイティブクラスを識別するために使用した文字列参照を覚えていますか。その文字列をCordova.plistファイルの実際のクラスインスタンスにマッピングする必要があります。Cordova.plistファイルには、現在のCordovaプロジェクトの設定情報がすべて格納されています。

  1. プロジェクトナビゲーターで、Supporting Filesフォルダーを開き、Cordova.plistという名前のファイルをクリックします。
  2. 右側でPluginsエントリまでスクロールダウンし、展開します。
  3. キーがcom.tricedesigns.HelloPlugin、値が「HelloPlugin」のエントリを追加し(図5を参照)、com.tricedesignsを自分の会社のIDに置き換えます。

     

    図5:Cordova.plistの編集
    図5:Cordova.plistの編集
     これは、Cordova.execを呼び出すときに3番目のパラメーターでネイティブクラスを識別するために使用した文字列参照です。キーはネイティブコードクラスにマッピングするためにPhoneGap.execで使用される固有の文字列参照です。値は呼び出される実際のネイティブクラスの名前です。
  4. 変更内容を保存します。

 これで、アプリケーションを起動してテストできます。アプリケーションを起動するには、「Run(実行)」ボタンをクリックするか、Product(製品)/Run(実行)を選択します。iOSシミュレーター(または接続したデバイス)でアプリケーションを起動すると、2つのボタンを持つ単純なインターフェイスが表示されます(図6を参照)。

図6:iOSシミュレーターで実行されたアプリケーション
図6:iOSシミュレーターで実行されたアプリケーション

 いずれかのボタンをクリックしてネイティブプラグインのネイティブコードを呼び出すと、成功または失敗のコールバック時にJavaScriptによってアラートメッセージが表示されます。

 ネイティブコードが呼び出されるときに、Xcodeデバッグコンソールで出力を確認することもできます。この出力は、ネイティブプラグインのNSLog呼び出しの出力を反映しています(図7を参照)。

図7:Xcodeデバッグコンソールのログ情報
図7:Xcodeデバッグコンソールのログ情報

次のステップ

 iOSデバイス用PhoneGapアプリケーションのネイティブプラグインを作成する方法をご理解いただけたでしょうか。このテクニックを利用して、Game Center、Core Audio、Bonjourフレームワークなど、核となるPhoneGap SDKによって公開されないiOSフレームワークや、その他のネイティブコードにアクセスできます。また、オープンソースコミュニティで開発された数々のGitHubのPhoneGapネイティブプラグインも参照してください。

 また、Adobe Developer ConnectionにPhoneGapデベロッパーセンターも開設されています。PhoneGap関連の記事はこちらで随時紹介していく予定ですので、ぜひご参照ください。

 この作品はCreative Commons Attribution-Noncommercial-Share Alike 3.0 Unported Licenseに基づき使用が許可されます。この作品に含まれるサンプルコードに関して、このライセンスの範囲を超えた使用の許可については、アドビのWebサイトを参照してください。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6689 2013/01/15 17:34

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング