Delphi 10.3 Rioがリリースされて約2ヶ月が経過し、Google Playの要件に対応するため、Android 8(API Level 26)への完全対応が実現されました。その中でも最も重要な機能はアプリケーションの動的権限要求です。以下では、独自アプリケーションで権限を動的に要求する方法について説明します。
以下のコードは、10.3でラップされたAndroid権限リストであり、これらのすべての権限を動的に要求することが可能です。
{class} property ACCESS_CHECKIN_PROPERTIES: JString read _GetACCESS_CHECKIN_PROPERTIES;
{class} property ACCESS_COARSE_LOCATION: JString read _GetACCESS_COARSE_LOCATION;
{class} property ACCESS_FINE_LOCATION: JString read _GetACCESS_FINE_LOCATION;
{class} property ACCESS_LOCATION_EXTRA_COMMANDS: JString read _GetACCESS_LOCATION_EXTRA_COMMANDS;
{class} property ACCESS_NETWORK_STATE: JString read _GetACCESS_NETWORK_STATE;
{class} property ACCESS_NOTIFICATION_POLICY: JString read _GetACCESS_NOTIFICATION_POLICY;
{class} property ACCESS_WIFI_STATE: JString read _GetACCESS_WIFI_STATE;
{class} property ACCOUNT_MANAGER: JString read _GetACCOUNT_MANAGER;
{class} property ADD_VOICEMAIL: JString read _GetADD_VOICEMAIL;
{class} property ANSWER_PHONE_CALLS: JString read _GetANSWER_PHONE_CALLS;
{class} property BATTERY_STATS: JString read _GetBATTERY_STATS;
{class} property BIND_ACCESSIBILITY_SERVICE: JString read _GetBIND_ACCESSIBILITY_SERVICE;
{class} property BIND_APPWIDGET: JString read _GetBIND_APPWIDGET;
{class} property BIND_AUTOFILL_SERVICE: JString read _GetBIND_AUTOFILL_SERVICE;
{class} property BIND_CARRIER_MESSAGING_SERVICE: JString read _GetBIND_CARRIER_MESSAGING_SERVICE;
{class} property BIND_CARRIER_SERVICES: JString read _GetBIND_CARRIER_SERVICES;
{class} property BIND_CHOOSER_TARGET_SERVICE: JString read _GetBIND_CHOOSER_TARGET_SERVICE;
{class} property BIND_CONDITION_PROVIDER_SERVICE: JString read _GetBIND_CONDITION_PROVIDER_SERVICE;
{class} property BIND_DEVICE_ADMIN: JString read _GetBIND_DEVICE_ADMIN;
{class} property BIND_DREAM_SERVICE: JString read _GetBIND_DREAM_SERVICE;
{class} property BIND_INCALL_SERVICE: JString read _GetBIND_INCALL_SERVICE;
{class} property BIND_INPUT_METHOD: JString read _GetBIND_INPUT_METHOD;
{class} property BIND_MIDI_DEVICE_SERVICE: JString read _GetBIND_MIDI_DEVICE_SERVICE;
{class} property BIND_NFC_SERVICE: JString read _GetBIND_NFC_SERVICE;
{class} property BIND_NOTIFICATION_LISTENER_SERVICE: JString read _GetBIND_NOTIFICATION_LISTENER_SERVICE;
{class} property BIND_PRINT_SERVICE: JString read _GetBIND_PRINT_SERVICE;
{class} property BIND_QUICK_SETTINGS_TILE: JString read _GetBIND_QUICK_SETTINGS_TILE;
{class} property BIND_REMOTEVIEWS: JString read _GetBIND_REMOTEVIEWS;
{class} property BIND_SCREENING_SERVICE: JString read _GetBIND_SCREENING_SERVICE;
{class} property BIND_TELECOM_CONNECTION_SERVICE: JString read _GetBIND_TELECOM_CONNECTION_SERVICE;
{class} property BIND_TEXT_SERVICE: JString read _GetBIND_TEXT_SERVICE;
{class} property BIND_TV_INPUT: JString read _GetBIND_TV_INPUT;
{class} property BIND_VISUAL_VOICEMAIL_SERVICE: JString read _GetBIND_VISUAL_VOICEMAIL_SERVICE;
{class} property BIND_VOICE_INTERACTION: JString read _GetBIND_VOICE_INTERACTION;
{class} property BIND_VPN_SERVICE: JString read _GetBIND_VPN_SERVICE;
{class} property BIND_VR_LISTENER_SERVICE: JString read _GetBIND_VR_LISTENER_SERVICE;
{class} property BIND_WALLPAPER: JString read _GetBIND_WALLPAPER;
{class} property BLUETOOTH: JString read _GetBLUETOOTH;
{class} property BLUETOOTH_ADMIN: JString read _GetBLUETOOTH_ADMIN;
{class} property BLUETOOTH_PRIVILEGED: JString read _GetBLUETOOTH_PRIVILEGED;
{class} property BODY_SENSORS: JString read _GetBODY_SENSORS;
{class} property BROADCAST_PACKAGE_REMOVED: JString read _GetBROADCAST_PACKAGE_REMOVED;
{class} property BROADCAST_SMS: JString read _GetBROADCAST_SMS;
{class} property BROADCAST_STICKY: JString read _GetBROADCAST_STICKY;
{class} property BROADCAST_WAP_PUSH: JString read _GetBROADCAST_WAP_PUSH;
{class} property CALL_PHONE: JString read _GetCALL_PHONE;
{class} property CALL_PRIVILEGED: JString read _GetCALL_PRIVILEGED;
{class} property CAMERA: JString read _GetCAMERA;
{class} property CAPTURE_AUDIO_OUTPUT: JString read _GetCAPTURE_AUDIO_OUTPUT;
{class} property CAPTURE_SECURE_VIDEO_OUTPUT: JString read _GetCAPTURE_SECURE_VIDEO_OUTPUT;
{class} property CAPTURE_VIDEO_OUTPUT: JString read _GetCAPTURE_VIDEO_OUTPUT;
{class} property CHANGE_COMPONENT_ENABLED_STATE: JString read _GetCHANGE_COMPONENT_ENABLED_STATE;
{class} property CHANGE_CONFIGURATION: JString read _GetCHANGE_CONFIGURATION;
{class} property CHANGE_NETWORK_STATE: JString read _GetCHANGE_NETWORK_STATE;
{class} property CHANGE_WIFI_MULTICAST_STATE: JString read _GetCHANGE_WIFI_MULTICAST_STATE;
{class} property CHANGE_WIFI_STATE: JString read _GetCHANGE_WIFI_STATE;
{class} property CLEAR_APP_CACHE: JString read _GetCLEAR_APP_CACHE;
{class} property CONTROL_LOCATION_UPDATES: JString read _GetCONTROL_LOCATION_UPDATES;
{class} property DELETE_CACHE_FILES: JString read _GetDELETE_CACHE_FILES;
{class} property DELETE_PACKAGES: JString read _GetDELETE_PACKAGES;
{class} property DIAGNOSTIC: JString read _GetDIAGNOSTIC;
{class} property DISABLE_KEYGUARD: JString read _GetDISABLE_KEYGUARD;
{class} property DUMP: JString read _GetDUMP;
{class} property EXPAND_STATUS_BAR: JString read _GetEXPAND_STATUS_BAR;
{class} property FACTORY_TEST: JString read _GetFACTORY_TEST;
{class} property GET_ACCOUNTS: JString read _GetGET_ACCOUNTS;
{class} property GET_ACCOUNTS_PRIVILEGED: JString read _GetGET_ACCOUNTS_PRIVILEGED;
{class} property GET_PACKAGE_SIZE: JString read _GetGET_PACKAGE_SIZE;
{class} property GET_TASKS: JString read _GetGET_TASKS;
{class} property GLOBAL_SEARCH: JString read _GetGLOBAL_SEARCH;
{class} property INSTALL_LOCATION_PROVIDER: JString read _GetINSTALL_LOCATION_PROVIDER;
{class} property INSTALL_PACKAGES: JString read _GetINSTALL_PACKAGES;
{class} property INSTALL_SHORTCUT: JString read _GetINSTALL_SHORTCUT;
{class} property INSTANT_APP_FOREGROUND_SERVICE: JString read _GetINSTANT_APP_FOREGROUND_SERVICE;
{class} property INTERNET: JString read _GetINTERNET;
{class} property KILL_BACKGROUND_PROCESSES: JString read _GetKILL_BACKGROUND_PROCESSES;
{class} property LOCATION_HARDWARE: JString read _GetLOCATION_HARDWARE;
{class} property MANAGE_DOCUMENTS: JString read _GetMANAGE_DOCUMENTS;
{class} property MANAGE_OWN_CALLS: JString read _GetMANAGE_OWN_CALLS;
{class} property MASTER_CLEAR: JString read _GetMASTER_CLEAR;
{class} property MEDIA_CONTENT_CONTROL: JString read _GetMEDIA_CONTENT_CONTROL;
{class} property MODIFY_AUDIO_SETTINGS: JString read _GetMODIFY_AUDIO_SETTINGS;
{class} property MODIFY_PHONE_STATE: JString read _GetMODIFY_PHONE_STATE;
{class} property MOUNT_FORMAT_FILESYSTEMS: JString read _GetMOUNT_FORMAT_FILESYSTEMS;
{class} property MOUNT_UNMOUNT_FILESYSTEMS: JString read _GetMOUNT_UNMOUNT_FILESYSTEMS;
{class} property NFC: JString read _GetNFC;
{class} property PACKAGE_USAGE_STATS: JString read _GetPACKAGE_USAGE_STATS;
{class} property PERSISTENT_ACTIVITY: JString read _GetPERSISTENT_ACTIVITY;
{class} property PROCESS_OUTGOING_CALLS: JString read _GetPROCESS_OUTGOING_CALLS;
{class} property READ_CALENDAR: JString read _GetREAD_CALENDAR;
{class} property READ_CALL_LOG: JString read _GetREAD_CALL_LOG;
{class} property READ_CONTACTS: JString read _GetREAD_CONTACTS;
{class} property READ_EXTERNAL_STORAGE: JString read _GetREAD_EXTERNAL_STORAGE;
{class} property READ_FRAME_BUFFER: JString read _GetREAD_FRAME_BUFFER;
{class} property READ_INPUT_STATE: JString read _GetREAD_INPUT_STATE;
{class} property READ_LOGS: JString read _GetREAD_LOGS;
{class} property READ_PHONE_NUMBERS: JString read _GetREAD_PHONE_NUMBERS;
{class} property READ_PHONE_STATE: JString read _GetREAD_PHONE_STATE;
{class} property READ_SMS: JString read _GetREAD_SMS;
{class} property READ_SYNC_SETTINGS: JString read _GetREAD_SYNC_SETTINGS;
{class} property READ_SYNC_STATS: JString read _GetREAD_SYNC_STATS;
{class} property READ_VOICEMAIL: JString read _GetREAD_VOICEMAIL;
{class} property REBOOT: JString read _GetREBOOT;
{class} property RECEIVE_BOOT_COMPLETED: JString read _GetRECEIVE_BOOT_COMPLETED;
{class} property RECEIVE_MMS: JString read _GetRECEIVE_MMS;
{class} property RECEIVE_SMS: JString read _GetRECEIVE_SMS;
{class} property RECEIVE_WAP_PUSH: JString read _GetRECEIVE_WAP_PUSH;
{class} property RECORD_AUDIO: JString read _GetRECORD_AUDIO;
{class} property REORDER_TASKS: JString read _GetREORDER_TASKS;
{class} property REQUEST_COMPANION_RUN_IN_BACKGROUND: JString read _GetREQUEST_COMPANION_RUN_IN_BACKGROUND;
{class} property REQUEST_COMPANION_USE_DATA_IN_BACKGROUND: JString read _GetREQUEST_COMPANION_USE_DATA_IN_BACKGROUND;
{class} property REQUEST_DELETE_PACKAGES: JString read _GetREQUEST_DELETE_PACKAGES;
{class} property REQUEST_IGNORE_BATTERY_OPTIMIZATIONS: JString read _GetREQUEST_IGNORE_BATTERY_OPTIMIZATIONS;
{class} property REQUEST_INSTALL_PACKAGES: JString read _GetREQUEST_INSTALL_PACKAGES;
{class} property RESTART_PACKAGES: JString read _GetRESTART_PACKAGES;
{class} property SEND_RESPOND_VIA_MESSAGE: JString read _GetSEND_RESPOND_VIA_MESSAGE;
{class} property SEND_SMS: JString read _GetSEND_SMS;
{class} property SET_ALARM: JString read _GetSET_ALARM;
{class} property SET_ALWAYS_FINISH: JString read _GetSET_ALWAYS_FINISH;
{class} property SET_ANIMATION_SCALE: JString read _GetSET_ANIMATION_SCALE;
{class} property SET_DEBUG_APP: JString read _GetSET_DEBUG_APP;
{class} property SET_PREFERRED_APPLICATIONS: JString read _GetSET_PREFERRED_APPLICATIONS;
{class} property SET_PROCESS_LIMIT: JString read _GetSET_PROCESS_LIMIT;
{class} property SET_TIME: JString read _GetSET_TIME;
{class} property SET_TIME_ZONE: JString read _GetSET_TIME_ZONE;
{class} property SET_WALLPAPER: JString read _GetSET_WALLPAPER;
{class} property SET_WALLPAPER_HINTS: JString read _GetSET_WALLPAPER_HINTS;
{class} property SIGNAL_PERSISTENT_PROCESSES: JString read _GetSIGNAL_PERSISTENT_PROCESSES;
{class} property STATUS_BAR: JString read _GetSTATUS_BAR;
{class} property SYSTEM_ALERT_WINDOW: JString read _GetSYSTEM_ALERT_WINDOW;
{class} property TRANSMIT_IR: JString read _GetTRANSMIT_IR;
{class} property UNINSTALL_SHORTCUT: JString read _GetUNINSTALL_SHORTCUT;
{class} property UPDATE_DEVICE_STATS: JString read _GetUPDATE_DEVICE_STATS;
{class} property USE_FINGERPRINT: JString read _GetUSE_FINGERPRINT;
{class} property USE_SIP: JString read _GetUSE_SIP;
{class} property VIBRATE: JString read _GetVIBRATE;
{class} property WAKE_LOCK: JString read _GetWAKE_LOCK;
{class} property WRITE_APN_SETTINGS: JString read _GetWRITE_APN_SETTINGS;
{class} property WRITE_CALENDAR: JString read _GetWRITE_CALENDAR;
{class} property WRITE_CALL_LOG: JString read _GetWRITE_CALL_LOG;
{class} property WRITE_CONTACTS: JString read _GetWRITE_CONTACTS;
{class} property WRITE_EXTERNAL_STORAGE: JString read _GetWRITE_EXTERNAL_STORAGE;
{class} property WRITE_GSERVICES: JString read _GetWRITE_GSERVICES;
{class} property WRITE_SECURE_SETTINGS: JString read _GetWRITE_SECURE_SETTINGS;
{class} property WRITE_SETTINGS: JString read _GetWRITE_SETTINGS;
{class} property WRITE_SYNC_SETTINGS: JString read _GetWRITE_SYNC_SETTINGS;
{class} property WRITE_VOICEMAIL: JString read _GetWRITE_VOICEMAIL上記のコードはAndroidapi.JNI.Osユニットに含まれており、**TJManifest_permission**クラスを通じて名前を取得できます。以下のコードのように、カメラの権限名を取得してPermissionCamera変数に格納します。
PermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA);アプリケーション実行中に権限を要求するために、10.3にはTPermissionsServiceというサービスクラスが実装されています。PermissionsServiceメソッドを使用してこのクラスのインスタンスを取得し、そのインスタンスのRequestPermissionsメソッドで権限を要求します。
PermissionsService.RequestPermissions([PermissionCamera, PermissionReadExternalStorage, PermissionWriteExternalStorage], OnPermissionCallback, OnRationaleDisplay);RequestPermissionsメソッドはその名前の通り権限を要求します。上記コードでは3つのパラメータを渡す必要があります。このメソッドのプロトタイプを見てみましょう。
procedure RequestPermissions(const APermissions: TArray<string>;
const AOnRequestPermissionsResult: TRequestPermissionsResultEvent; AOnDisplayRationale: TDisplayRationaleEvent = nil);
overload; virtual;APermissions:権限名の配列、例えば:[PermissionCamera, PermissionReadExternalStorage, PermissionWriteExternalStorage]
AOnRequestPermissionsResult:TRequestPermissionsResultEvent型、権限要求後に発生するイベントです。動的権限要求後のロジックを処理するためのTRequestPermissionsResultEvent関数を作成する必要があります。
AOnDisplayRationale:TDisplayRationaleEvent型、このイベントを使用してユーザーに権限要求の理由を非同期に表示します。ユーザーが説明を見た後、コードを通じてユーザーが権限をさらに要求できるようにします。このスレッドをユーザーレスポンス待ちでブロックしないように注意してください!
以上を踏まえて、動的権限要求を実装する手順を見てみましょう。
1. アプリが必要とする権限名の変数を宣言します
// 動的権限要求
PermissionCamera,
PermissionReadExternalStorage,
PermissionWriteExternalStorage: string;2. アプリ起動時にTJManifest_permissionを通じて権限名を取得し、権限名変数に代入します
procedure TMainForm.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
PermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA);
PermissionReadExternalStorage := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
PermissionWriteExternalStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
{$ENDIF}次に、PermissionsService.RequestPermissionsメソッドのパラメータとして使用する2つのメソッドを準備し、権限要求時のコールバック関数として権限要求の結果とユーザーへの権限説明情報を処理します。
3. TRequestPermissionsResultEventメソッドを実装します
procedure TMainForm.OnPermissionCallback(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>);
begin
// 要求された3つの権限: CAMERA, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE
if (Length(AGrantResults) = 3) and
(AGrantResults[0] = TPermissionStatus.Granted) and
(AGrantResults[1] = TPermissionStatus.Granted) and
(AGrantResults[2] = TPermissionStatus.Granted) then
begin
// ユーザーが権限を許可した場合のコード
ShowMessage('すべての権限が承認されました');
end
else
begin
// ユーザーが権限を拒否した場合のコード
TDialogService.ShowMessage('権限が拒否されたため、機能が利用できません。');
end;
end;4. TDisplayRationaleEventメソッドを実装します
procedure TMainForm.OnRationaleDisplay(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc);
var
Index: Integer;
RationaleMessage: string;
begin
for Index := 0 to High(APermissions) do
begin
if APermissions[Index] = PermissionCamera then
RationaleMessage := RationaleMessage + '写真撮影のためにカメラアクセスが必要です。' + SLineBreak + SLineBreak
else if APermissions[Index] = PermissionReadExternalStorage then
RationaleMessage := RationaleMessage + '外部ストレージ読み取りアクセスが必要です。';
end;
TDialogService.MessageDialog(RationaleMessage,
procedure(const AResult: TModalResult)
begin
APostRationaleProc();
end);
end;5. アプリ起動時にPermissionsService.RequestPermissionsを使用して権限を要求します
procedure TMainForm.FormCreate(Sender: TObject);
begin
{$IFDEF ANDROID}
PermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA);
PermissionReadExternalStorage := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE);
PermissionWriteExternalStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE);
{$ENDIF}
PermissionsService.RequestPermissions([PermissionCamera, PermissionReadExternalStorage, PermissionWriteExternalStorage],
OnPermissionCallback,
OnRationaleDisplay);
end;これで動的権限要求が実装されました。公式が提供した参考コード:
procedure TLocationForm.ToggleLocationSensor(Sender: TObject);
begin
{$IFDEF ANDROID}
if LocationToggleSwitch.IsChecked then
PermissionsService.RequestPermissions([JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION)],
procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then
LocationSensor.Active := True
else
begin
LocationToggleSwitch.IsChecked := False;
TDialogService.ShowMessage('位置情報の権限が付与されませんでした');
end;
end)
else
{$ENDIF}
LocationSensor.Active := False;
end;