Android サービスの作成
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 という名前で表示されます。
- ビジュアル コンポーネントをデータ モジュールに、関数と手続きをコードに追加します。
- Android サービス プロジェクトを保存します。
- メモ 1: Android サービス プロジェクトは、それぞれ異なるフォルダに保存してください。
- メモ 2: Android サービス プロジェクトに Service という名前を付けてはなりません。
- Android サービス プロジェクトをビルドしてからアプリケーションに追加し、バイナリ ファイルを生成します。
- サービスを追加する先のアプリケーションを[プロジェクト マネージャ]に追加します。
- 既存のアプリケーションの場合には、プロジェクト グループを右クリックし、[既存プロジェクトを追加...]を選択します。
- マルチデバイス アプリケーションを新規作成する場合は、プロジェクト グループを右クリックし、[新規プロジェクトを追加...]を選択してから、以下を選択します。
- [Delphi プロジェクト|マルチデバイス アプリケーション]
- そのマルチデバイス アプリケーションで、ターゲット プラットフォームに[Android]を選択します。
- [完了]をクリックすると、以下のファイルがアプリケーションに追加されます。
- メインのバイナリ ファイル、lib<プロジェクト名>.so。バイナリ ファイルは配置マネージャに追加されます。
- メモ: このメモは、RAD Studio Seattle Subscription Update 1 に影響しません。lib<プロジェクト名>.so へのローカル パスは絶対パスです。サービスの場所を別の位置に変更する場合には、サービスを再びアプリケーションに追加する必要があります。
- libProxyAndroidService.so ファイル。このライブラリは配置マネージャに追加されます。
- メモ: このファイルは、アプリケーションに追加されたすべてのサービスで共有されます。
- Java アーカイブ ファイル <プロジェクト名>.jar。この jar ファイルは、[プロジェクト マネージャ]の[Android]ターゲット プラットフォームの下にある[ライブラリ]ノードに追加されます。
- データ モジュール ファイル <プロジェクト名>.pas。このデータ モジュールは[プロジェクト マネージャ]に追加されます。
- メインのバイナリ ファイル、lib<プロジェクト名>.so。バイナリ ファイルは配置マネージャに追加されます。
- マルチデバイス アプリケーションをコンパイルして Android マニフェスト ファイルを生成し、先ほど選択したサービスの種類(ローカルまたはリモート)に応じた行を追加します。詳細は、「Android サービスの作成」を参照してください。
- メモ: サービスごとに、対応する <service> の宣言を AndroidManifest.xml に追加する必要があります。これは IDE によって自動的に追加されます。
アプリケーションへの複数の Android サービスの追加
任意の数のサービスを Android アプリケーションに追加することができます。
追加するサービスそれぞれについて、「アプリケーションへの Android サービスの追加」の手順を実施してください。
以下はその際の注意事項です。
- Android サービス プロジェクトは、それぞれ異なるフォルダに保存してください。
- プロジェクトそれぞれに異なる名前を付けてから、メイン アプリケーションに追加します。
- Android サービス プロジェクト:lib<サービス名>.so。
-
- メモ: Android サービス プロジェクトに Service という名前を付けてはなりません。
- ユニット ファイル。
- データ モジュール: [オブジェクト インスペクタ]の Name プロパティで名前を変更できます。
アプリケーションからの Android サービスの削除
既に Android アプリケーションに追加された Android サービスの削除は手動で行います。手順は以下のとおりです。
- Java アーカイブを削除します。
[プロジェクト マネージャ]の[Android]ターゲット プラットフォームで以下を行います。
- [ライブラリ]ノードを開き、<サービス名>.jar を選択します。
- 右クリックして[プロジェクトから削除...]を選択します。
- モーダル ダイアログで[はい]をクリックして操作を承認します。
- データ モジュールを削除します。
[プロジェクト マネージャ]で以下を行います。
- [サービス]ノードを開き、<サービス名>.pas を選択します。
- 右クリックして[プロジェクトから削除...]を選択します。
- モーダル ダイアログで[はい]をクリックして操作を承認します。
- バイナリ ファイルを、配置マネージャから削除します。
- lib<サービス名>.so(<サービス名> に固有)。
- libProxyAndroidService.so (すべてのサービスによって共有)。
- メモ: アプリケーションに他のサービスが含まれている場合には、libProxyAndroidService.so ライブラリのチェックをオフにしないでください。これはすべてのサービスで共有されるファイルです。
メモ: 以下は、RAD Studio Seattle Subscription Update 1 に影響しません。
種類が AndroidServiceOutput のファイルは配置マネージャから削除することができません。
ファイルのターゲット マシンへの配置を無効化するには:
- lib<サービス名>.so を選択し、 のチェックをオフにします。
- libProxyAndroidService.so を選択し、 のチェックをオフにします。
- メモ: アプリケーションに他のサービスが含まれている場合には、libProxyAndroidService.so ライブラリのチェックをオフにしないでください。これはすべてのサービスで共有されるファイルです。
また、[デフォルトに戻す]コマンド ボタン()を使用すると、現在のプロジェクトに対して配置マネージャで行った変更をすべて元に戻すことができます。
- メモ 1: 複数のサービスをプロジェクトに追加していてそのすべてを削除したいわけではない場合や、行った他の変更を元に戻したくない場合には、このオプションを使用しないでください。
- メモ 2: 手動でプロジェクトに追加したファイルを残すには、[デフォルトに戻す]のウィンドウで、[追加したファイルを保持する]オプションを忘れずにオンにしてください。
サービスの起動
サービスは、ALocalServiceConnection.StartService('<サービス名>') と ALocalServiceConnection.BindService('<サービス名>')、または ARemoteServiceConnection.StartService('<サービス名>') と ARemoteServiceConnection.BindService('<サービス名>') を使って起動することができます。
起動時またはバインド時に、TLocalServiceConnection 変数を具体的なサービスに初期化します。その後、残りのメソッドでサービス名を参照する必要はありません。
Android サービスをマルチデバイス アプリケーションに追加したら、以下を行います。
- 以下のユニットをインターフェイスの uses 句 に追加します。
Uses System.Android.Service; // Unit that contains the methods to work with services.
- <サービス名>.pas ユニットを実装の uses 句に追加します。これで、サービス データ モジュールに定義されたすべてのメソッドを使用できるようになります。
implementation uses MyLocalService; //Key sensitive {$R *.fmx}
- ローカル サービスの場合は TLocalServiceConnetion 変数、リモート サービスの場合は TRemoteServiceConnection 変数を作成します。
- 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;
- TLocalServiceConnection/TRemoteServiceConnection 変数を作成します。
FServiceConnection1 := TLocalServiceConnection.Create; // For a local service. FServiceConnection2 := TRemoteServiceConnection.Create; // For a remote service.
- TLocalServiceConnection/TRemoteServiceConnection 変数を宣言します。
起動型サービス
起動型サービスの場合は、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 つあります。
- <sectionName>Unsafe 属性</sectionName>[UnSafe] 属性を使用して自動参照カウントを使わないようにする
- サービスとのバインドを解除する前に変数に
Nil
を代入する
[Unsafe] 属性の利用
private
{ Private declarations }
[Unsafe] Service1: TAndroidService1DM;
詳細は、「Unsafe 属性」を参照してください。
OnBind イベント
アプリケーションの BindService('<サービス名>')
を呼び出すと、Android サービス プロジェクトで OnBind イベントが発生します。OnBind メソッドは、サービスとの接続を実際に管理する責任を負う IBinder オブジェクトを返します。
OnBind メソッドを上書きすると、メイン アプリケーションがサービスからデータ モジュールを取り出すために必要な IBinder オブジェクトが、イベントから返されなくなります。
以下のコードは、OnBind メソッドを使用する必要がある上級ユーザー向けです。
- 以下のユニットをインターフェイスの uses 句 に追加します。
uses Androidapi.Jni, Androidapi.JNIBridge;
- 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;
- 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 を含めるには:
- Android サービス プロジェクトから、残っている他の lib<サービス名>.so ファイルをすべて削除します。
- Android サービス プロジェクトを Release 構成でコンパイルします。
- Android サービスをホスト アプリケーションの Release 構成に追加してから、アプリケーションを Android デバイスに配置します。
- メモ: [Android サービスの追加...]のウィザードで追加するファイルを選択します。