Android サービスの作成

提供: RAD Studio
移動先: 案内検索

Android アプリケーションの作成 への移動

Android サービスとは、ユーザー インターフェイスを持たない、バックグラウンド タスクを実行するアプリケーションです。このサービスには、本質的に以下の 2 種類があります。

  • 起動型サービス: このサービスは Android アプリケーションによって起動されます。サービスは、アプリケーションが終了した後も、バックグラウンドで無期限に動作し続けることができます。この種類のサービスは、通常、1 つのタスクを実行し、それが終了すると自動的に停止します。
  • バインド型サービス: このサービスは、Android アプリケーションにバインドされている間のみ動作します。アプリケーションとサービスの間で対話が行われ、アプリケーションがバインドを解除するまでアクティブなままになります。複数のアプリケーションを同じ 1 つのサービスにバインドすることができます。

Android サービスの作成

RAD Studio では、Android サービス プロジェクトを作成するウィザードと、マルチデバイス アプリケーションに Android サービスを追加するための別のウィザードが用意されています。

Android サービス プロジェクトを新規作成するには、[ファイル|新規作成|その他...]を選択し、それから以下を選択します。

  • [Delphi プロジェクト|Android サービス]

このウィザードで、サービスの種類(ローカルまたはリモート)を指定します。

  • ローカル サービスは、そのアプリケーションだけで使用できる private のサービスです。Android マニフェスト ファイルに以下の行が追加され、他のアプリケーションからのアクセスが阻止されます。
<service android:exported="false" android:name="com.embarcadero.services.<service_name>"/>
  • リモート サービスは public であり、他のアプリケーションからアクセスすることができます。Android マニフェスト ファイルに以下の行が追加され、サービスへのアクセスが認められます。
<service android:exported="true" android:name="com.embarcadero.services.<service_name>"/>

さまざまなオプションの詳細は、「Android サービス」を参照してください。

Android マニフェスト属性の詳細は、「Exported Provider Element(provider 要素のエクスポート)」を参照してください。

アプリケーションへの Android サービスの追加

作成したサービスは、[プロジェクト マネージャ]に lib<プロジェクト名>.so という名前で表示されます。

  1. ビジュアル コンポーネントをデータ モジュールに、関数と手続きをコードに追加します。
  2. Android サービス プロジェクトを保存します。
    メモ 1: Android サービス プロジェクトは、それぞれ異なるフォルダに保存してください。
    メモ 2: Android サービス プロジェクトに Service という名前を付けてはなりません。
  3. Android サービス プロジェクトをビルドしてからアプリケーションに追加し、バイナリ ファイルを生成します。
  4. サービスを追加する先のアプリケーションを[プロジェクト マネージャ]に追加します。
    1. 既存のアプリケーションの場合には、プロジェクト グループを右クリックし、[既存プロジェクトを追加...]を選択します。
    2. マルチデバイス アプリケーションを新規作成する場合は、プロジェクト グループを右クリックし、[新規プロジェクトを追加...]を選択してから、以下を選択します。
      • [Delphi プロジェクト|マルチデバイス アプリケーション]
  5. そのマルチデバイス アプリケーションで、ターゲット プラットフォームに[Android]を選択します。
    1. [Android]ターゲット プラットフォームを右クリックし、[Android サービスの追加...]を選択します。
    2. [新規 Android サービスの追加]ウィザードが開きます。
    3. ProjectOptionsEllipsis.jpg をクリックして、Android サービス プロジェクトを保存するフォルダを選択します。
    4. [次へ]をクリックします。
      1. 何も問題なければ、マルチデバイス アプリケーションに追加されるファイルがリストに表示されます。
      2. Android サービスのパスの情報を要求するウィンドウが開いた場合には、Android サービスを保存しビルドしてからやり直してください。
  6. [完了]をクリックすると、以下のファイルがアプリケーションに追加されます。
    • メインのバイナリ ファイル、lib<プロジェクト名>.so。バイナリ ファイルは配置マネージャに追加されます。
      メモ: このメモは、RAD Studio Seattle Subscription Update 1 に影響しません。lib<プロジェクト名>.so へのローカル パスは絶対パスです。サービスの場所を別の位置に変更する場合には、サービスを再びアプリケーションに追加する必要があります。
    • libProxyAndroidService.so ファイル。このライブラリは配置マネージャに追加されます。
      メモ: このファイルは、アプリケーションに追加されたすべてのサービスで共有されます。
    • Java アーカイブ ファイル <プロジェクト名>.jar。この jar ファイルは、[プロジェクト マネージャ]の[Android]ターゲット プラットフォームの下にある[ライブラリ]ノードに追加されます。
    • データ モジュール ファイル <プロジェクト名>.pas。このデータ モジュールは[プロジェクト マネージャ]に追加されます。
  7. マルチデバイス アプリケーションをコンパイルして Android マニフェスト ファイルを生成し、先ほど選択したサービスの種類(ローカルまたはリモート)に応じた行を追加します。詳細は、「Android サービスの作成」を参照してください。
    メモ: サービスごとに、対応する <service> の宣言を AndroidManifest.xml に追加する必要があります。これは IDE によって自動的に追加されます。

アプリケーションへの複数の Android サービスの追加

任意の数のサービスを Android アプリケーションに追加することができます。

追加するサービスそれぞれについて、「アプリケーションへの Android サービスの追加」の手順を実施してください。

以下はその際の注意事項です。

  • Android サービス プロジェクトは、それぞれ異なるフォルダに保存してください。
  • プロジェクトそれぞれに異なる名前を付けてから、メイン アプリケーションに追加します。
    • Android サービス プロジェクト:lib<サービス名>.so。
    メモ: Android サービス プロジェクトに Service という名前を付けてはなりません。

アプリケーションからの Android サービスの削除

既に Android アプリケーションに追加された Android サービスの削除は手動で行います。手順は以下のとおりです。

  1. Java アーカイブを削除します。 [プロジェクト マネージャ]の[Android]ターゲット プラットフォームで以下を行います。
    1. [ライブラリ]ノードを開き、<サービス名>.jar を選択します。
    2. 右クリックして[プロジェクトから削除...]を選択します。
    3. モーダル ダイアログで[はい]をクリックして操作を承認します。
  2. データ モジュールを削除します。 [プロジェクト マネージャ]で以下を行います。
    1. [サービス]ノードを開き、<サービス名>.pas を選択します。
    2. 右クリックして[プロジェクトから削除...]を選択します。
    3. モーダル ダイアログで[はい]をクリックして操作を承認します。
  3. バイナリ ファイルを、配置マネージャから削除します。
    • lib<サービス名>.so(<サービス名> に固有)。
    • libProxyAndroidService.so (すべてのサービスによって共有)。
      メモ: アプリケーションに他のサービスが含まれている場合には、libProxyAndroidService.so ライブラリのチェックをオフにしないでください。これはすべてのサービスで共有されるファイルです。

メモ: 以下は、RAD Studio Seattle Subscription Update 1 に影響しません。

種類が AndroidServiceOutput のファイルは配置マネージャから削除することができません。

ファイルのターゲット マシンへの配置を無効化するには:

  • lib<サービス名>.so を選択し、Chekbox.png のチェックをオフにします。
  • libProxyAndroidService.so を選択し、Chekbox.png のチェックをオフにします。
    メモ: アプリケーションに他のサービスが含まれている場合には、libProxyAndroidService.so ライブラリのチェックをオフにしないでください。これはすべてのサービスで共有されるファイルです。

また、[デフォルトに戻す]コマンド ボタン(DMgrRevert.png)を使用すると、現在のプロジェクトに対して配置マネージャで行った変更をすべて元に戻すことができます。

メモ 1: 複数のサービスをプロジェクトに追加していてそのすべてを削除したいわけではない場合や、行った他の変更を元に戻したくない場合には、このオプションを使用しないでください。
メモ 2: 手動でプロジェクトに追加したファイルを残すには、[デフォルトに戻す]のウィンドウで、[追加したファイルを保持する]オプションを忘れずにオンにしてください。

サービスの起動

サービスは、ALocalServiceConnection.StartService('<サービス名>')ALocalServiceConnection.BindService('<サービス名>')、または ARemoteServiceConnection.StartService('<サービス名>')ARemoteServiceConnection.BindService('<サービス名>') を使って起動することができます。

起動時またはバインド時に、TLocalServiceConnection 変数を具体的なサービスに初期化します。その後、残りのメソッドでサービス名を参照する必要はありません。

Android サービスをマルチデバイス アプリケーションに追加したら、以下を行います。

  1. 以下のユニットをインターフェイスの uses 句 に追加します。
    Uses
      System.Android.Service; // Unit that contains the methods to work with services.
    
  2. <サービス名>.pas ユニットを実装の uses 句に追加します。これで、サービス データ モジュールに定義されたすべてのメソッドを使用できるようになります。
    implementation
    
    uses
      MyLocalService; //Key sensitive
    
    {$R *.fmx}
    
  3. ローカル サービスの場合は TLocalServiceConnetion 変数、リモート サービスの場合は TRemoteServiceConnection 変数を作成します。
    1. TLocalServiceConnection/TRemoteServiceConnection 変数を宣言します。
      type
        TForm1 = class(TForm)
          ...
        private
          { Private declarations }
          FServiceConnection1: TLocalServiceConnection; // For a local service.
          FServiceConnection2: TRemoteServiceConnection; // For a remote service.
        public
          { Public declarations }
        end;
      
    2. TLocalServiceConnection/TRemoteServiceConnection 変数を作成します。
      FServiceConnection1 := TLocalServiceConnection.Create; // For a local service.
      FServiceConnection2 := TRemoteServiceConnection.Create; // For a remote service.
      

起動型サービス

起動型サービスの場合は、StartService('<サービス名>') を呼び出してサービスを起動します。

サービスを起動型として使用する場合、自分でサービス プロセスを管理し、JavaService.stopSelf; を使ってサービスを停止する必要があります。

スティッキーでの起動

サービスの OnStartCommand イベントは、デフォルトでは START_NOT_STICKY と定義されています。

  • START_STICKY は、明示的に起動され、必要に応じて停止されるサービスに使用します。システムは、サービスが強制終了されると、サービスの再起動を試みます。
  • START_NOT_STICKY は、送られてきたコマンドを処理する間だけ実行しておきたいサービスに使用します。プロセスが強制終了されても、サービスは自動的に再起動されません。

OnStartCommand イベントを START_STICKY にしたい場合は、それをサービスに指定する必要があります。

function TService1DM.AndroidServiceStartCommand(const Sender: TObject;
  const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  Result := TJService.JavaClass.START_STICKY;
end;

詳細は、「Service Lifecycle(サービスのライフサイクル)」を参照してください。

バインド型サービス

バインド型サービスの場合は、BindService('<サービス名>') を呼び出してサービスをバインドし、対話を始められるようにしたり、UnBindService を呼び出してサービスとの接続を解除します。

詳細は、「Bound Services(バインド型サービス)」を参照してください。

BindService/UnBindService メソッド

メイン アプリケーションで BindService('<サービス名>') を呼び出すと、サービスが動作しているメモリ アドレスを指すポインタが接続変数に設定されます。

特定のサービスに対する接続を確立した後で、UnBindService を呼び出したときに、そのサービスにバインドしているのがそのアプリケーションだけであれば、サービスは自身を解放します。メイン アプリケーションの接続変数は、同じメモリ アドレスを指したままになることに注意してください。同じサービスに再びバインドするとメイン アプリケーションがクラッシュする可能性があります。サービスのメモリ アドレスが無効である可能性があるためです。

この状況に対処する方法は 2 つあります。

[Unsafe] 属性の利用

  private
    { Private declarations }
    [Unsafe] Service1: TAndroidService1DM;

詳細は、「Unsafe 属性」を参照してください。

OnBind イベント

アプリケーションの BindService('<サービス名>') を呼び出すと、Android サービス プロジェクトで OnBind イベントが発生します。OnBind メソッドは、サービスとの接続を実際に管理する責任を負う IBinder オブジェクトを返します。

OnBind メソッドを上書きすると、メイン アプリケーションがサービスからデータ モジュールを取り出すために必要な IBinder オブジェクトが、イベントから返されなくなります。

以下のコードは、OnBind メソッドを使用する必要がある上級ユーザー向けです。

  1. 以下のユニットをインターフェイスの uses 句 に追加します。
    uses
      Androidapi.Jni, Androidapi.JNIBridge;
    
  2. IBinder オブジェクトを取得する関数を作成します。
    function GetBinder(const AService: TAndroidBaseService): JIBinder;
    
      function GetmBinder(AJNIService: JNIObject): JIBinder;
      var
        Env: PJNIEnv;
        Clazz: JNIClass;
        FieldID: JNIFieldID;
        LJNIBinder: JNIObject;
      begin
        Result := nil;
        PJavaVM(System.JavaMachine)^.AttachCurrentThread(System.JavaMachine, @Env, nil);
        Clazz := Env^.GetObjectClass(Env, AJNIService);
        FieldID := Env^.GetFieldID(Env, Clazz, 'mBinder', 'Landroid/os/IBinder;');
        if FieldID <> nil then
        begin
          LJNIBinder := Env^.GetObjectField(Env, AJNIService, FieldID);
          if LJNIBinder <> nil then
          begin
            Result := TJIBinder.Wrap(LJNIBinder);
            Env^.DeleteLocalRef(Env, LJNIBinder);
          end;
        end;
        Env^.DeleteLocalRef(Env, Clazz);
      end;
    
    begin
      if AService.JavaService <> nil then
        Result := GetmBinder((AService.JavaService as ILocalObject).GetObjectID)
      else if AService.JavaIntentService <> nil then
        Result := GetmBinder((AService.JavaIntentService as ILocalObject).GetObjectID)
      else
        Result := nil;
    end;
    
  3. OnBind メソッドで IBinder オブジェクトを返します。
    function TAndroidServiceDM.AndroidServiceBind(const Sender: TObject;
      const AnIntent: JIntent): JIBinder;
    begin
      // .... User's code
      Result := GetBinder(Self);
    end;
    

トラブルシューティング

配置前のビルド構成の変更

RAD Studio で Android サービスを構成するファイルの 1 つに、lib<サービス名>.so があります。このライブラリ ファイルは、Android サービスのコンパイル時に生成され、デフォルトでは .\$(Platform)\$(Config) に保存されます。

ホスト アプリケーションに Android サービスを追加すると、ライブラリ ファイル lib<サービス名>.so は、Debug など、配置マネージャで選択したビルド構成に追加されます。Release などの別のビルド構成を選択して Android アプリケーションを配置すると、必要なファイルが配置マネージャに自動的に追加されないため配置されず、実行時エラーが発生します。

必要なファイルを正しいビルド構成に追加するには、サービスをメイン アプリケーションに追加し直してください。

Release lib<サービス名>.so の追加

ホスト アプリケーションに Debug lib<サービス名>.so ではなく Release lib<サービス名>.so を含めるには:

  1. Android サービス プロジェクトから、残っている他の lib<サービス名>.so ファイルをすべて削除します。
  2. Android サービス プロジェクトを Release 構成でコンパイルします。
  3. Android サービスをホスト アプリケーションの Release 構成に追加してから、アプリケーションを Android デバイスに配置します。
    メモ: [Android サービスの追加...]のウィザードで追加するファイルを選択します。

関連項目