delphi安卓动态权限申请
delphi安卓动态权限申请
安卓8及以上版本,除了原来的静态权限申请以外,还需要动态权限申请。
delphi10.3开始支持安卓动态权限申请。
delphi11开始官方改变了安卓动态权限申请的参数类型,导致原来编写的代码,编码报错。
下面的代码,可以很好地解决权限问题。兼顾了delphi10.3和delphi11以后版本。
{sensor 2022-07-12 周二 老吴QQ:910731685
Android 动态申请权限控件
参考:https://developer.android.google.cn/reference/android/Manifest.permission
}
unit uAndroid_Permissions_Component;
interface
uses
System.Types, //TClassicStringDynArray
System.Permissions, //TClassicPermissionStatusDynArray
FMX.DialogService,
System.UITypes, //TModalResult
System.TypInfo,
{$IFDEF DEBUG}
FMX.Dialogs,
{$ENDIF}
System.SysUtils,
System.Classes;
const
Permission_Prefix = 'android.permission.'; //Android 权限字符串的前缀部分
type
//如果授权申请成功, GrantedResult=true,NoGranteds无效,否则 GrantedResult=false,NoGranteds表示没有授权的项目列表
TApplyResult = procedure(const Sender : TObject; GrantedResult : Boolean; NoGranteds : TArray<string>) of object;
TPermission = (
ACCESS_COARSE_LOCATION, //可单独申请 获取大致位置信息Allows an app to access approximate location.
ACCESS_FINE_LOCATION, //可单独申请 获取精确位置信息Allows an app to access precise location.
ACCESS_BACKGROUND_LOCATION, //Androidapi.JNI.Os 没有包含这个权限,实际是支持的。这个权限必须要求ACCESS_COARSE_LOCATION 和 ACCESS_FINE_LOCATION 权限
ACCESS_MEDIA_LOCATION, //可单独申请 Allows an application to access any geographic locations persisted in the user's shared collection
//ACCESS_MOCK_LOCATION, //(obsolete) Android目前已经不支持
ACTIVITY_RECOGNITION, // 获取设备中的健身运动信息 Allows an application to recognize physical activity.
ADD_VOICEMAIL, // Allows an application to add voicemails into the system.
ANSWER_PHONE_CALLS, // 接听或挂断电话、监听通话状态
//AUTHENTICATE_ACCOUNTS, // (obsolete) Android目前已经不支持
BODY_SENSORS, //获取您的生命体征相关数据
BODY_SENSORS_BACKGROUND, // API 33 新增加 后台获取您的生命体征相关数据
CALL_PHONE,
CAMERA,
//CONYINUE_A_CALL_STARTED_IN_ANOTHER_APP, // Android目前已经不支持 Continue a call started in another app
GET_ACCOUNTS, //获取手机账户
MANAGE_ACCOUNTS, // Android目前已经不支持 Manage accounts (obsolete)
//PROCESS_OUTGOING_CALLS, //
READ_CALENDAR, //读取日历中的日程信息
READ_CALL_LOG, //读取通话记录
READ_CONTACTS, //读取联系人信息
READ_EXTERNAL_STORAGE, //读取设备上的照片及文件
//READ_HISTORY_BOOKMARKS, //Android目前已经不支持 Read history bookmarks (obsolete)
READ_PHONE_NUMBERS,
READ_PHONE_STATE,
READ_SMS,
RECEIVE_MMS,
RECEIVE_SMS,
RECEIVE_WAP_PUSH,
RECORD_AUDIO,
SEND_SMS,
USE_SIP,
WRITE_CALENDAR,
WRITE_CALL_LOG,
WRITE_CONTACTS,
WRITE_EXTERNAL_STORAGE
);
TPermissions = set of TPermission;
TAndroid_Permission = class(TComponent)
private
FOnApplyResult : TApplyResult;
FPermissions : TPermissions;
FPermissionsStr: TArray<string>;
procedure SetFPermissions(value: TPermissions);
// **** 关于 Android 权限相关 ****
procedure DisplayRationale(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);
{$IF CompilerVersion >= 35.0}
// after Delphi 11 Alexandria
procedure AndroidPermissionRequestResult(Sender: TObject;
const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray);
{$ELSE}
// before Delphi 11 Alexandria
procedure AndroidPermissionRequestResult(const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>);
{$ENDIF}
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
//申请权限
procedure Apply;
//检测权限是否已经授予
function IsPermissionGranted(APermission : string): Boolean;
published
property Permissions: TPermissions read FPermissions write SetFPermissions;
property OnApplyResult : TApplyResult read FOnApplyResult write FOnApplyResult;
end;
//procedure Register;
implementation
//{$R 'Android_Permission.dcr'}
//procedure Register;
//begin
// RegisterComponents('LW', [TAndroid_Permission]);
//end;
{ TAndroid_Permission }
{$IF CompilerVersion >= 35.0}
procedure TAndroid_Permission.AndroidPermissionRequestResult(Sender: TObject;
const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray);
var
i,count : integer;
NoGranteds : TArray<string>;
begin
// 判断是否申请的授权都已经批准
SetLength(NoGranteds,0);
count := Length(FPermissionsStr);
for i := 0 to count - 1 do //逐条判断是否已经成功授权
begin
{$IFDEF DEBUG}
showmessage(GetEnumName(typeInfo(TPermissionStatus), Ord(AGrantResults[i])) + ' : '#13#10 + FPermissionsStr[i]);
{$ENDIF}
if AGrantResults[i] <> TPermissionStatus.Granted then
begin
SetLength(NoGranteds,Length(NoGranteds) + 1);
NoGranteds[Length(NoGranteds) - 1] := FPermissionsStr[i];
end;
end;
if Length(NoGranteds) = 0 then
begin
if Assigned(FOnApplyResult) then //此时授权已经全部成功,可以触发授权成功事件
try
FOnApplyResult(Self,True,[]); //防止用户事件出错,导致控件错误
except on E: Exception do
raise Exception.Create('OnApplyResult: ' + E.message);
end;
end
else
if Assigned(FOnApplyResult) then //此时授权已经全部成功,可以触发授权成功事件
try
FOnApplyResult(Self,False,NoGranteds); //防止用户事件出错,导致控件错误
except on E: Exception do
raise Exception.Create('OnApplyResult: ' + E.message);
end;
end;
{$ELSE}
procedure AndroidPermissionRequestResult(const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>);
var
i,count : integer;
NoGranteds : TArray<string>;
begin
// 判断是否申请的授权都已经批准
SetLength(NoGranteds,0);
count := Length(FPermissionsStr);
for i := 0 to count - 1 do //逐条判断是否已经成功授权
begin
if AGrantResults[i] <> TPermissionStatus.Granted then
begin
SetLength(NoGranteds,Length(NoGranteds) + 1);
NoGranteds[Length(NoGranteds) - 1] := FPermissionsStr[i];
end;
end;
if Length(NoGranteds) = 0 then
begin
if Assigned(FOnApplyResult) then //此时授权已经全部成功,可以触发授权成功事件
try
FOnApplyResult(Self,True,[]); //防止用户事件出错,导致控件错误
except on E: Exception do
raise Exception.Create('OnApplyResult: ' + E.message);
end;
end
else
if Assigned(FOnApplyResult) then //此时授权已经全部成功,可以触发授权成功事件
try
FOnApplyResult(Self,False,NoGranteds); //防止用户事件出错,导致控件错误
except on E: Exception do
raise Exception.Create('OnApplyResult: ' + E.message);
end;
end;
{$ENDIF}
procedure TAndroid_Permission.Apply;
var
Permission : TPermission;
i : Integer;
{$IFDEF DEBUG}
count : integer;
S : string;
{$ENDIF}
PermissionStr : string;
begin
{$IFNDEF ANDROID}
Exit; //只有android 环境下动态申请权限才有效
{$ENDIF}
//确认只有 10.3 及以上的版本编译才有效
{$IF CompilerVersion < 33.0} //10.3 Rio
Exit; //10.3 以下不支持
{$ELSE}
if (TOSVersion.Major <= 6) then Exit; //只有Android 7 以上才支持动态权限,实际上7没有反应,8才真正支持动态权限申请
{$ENDIF}
SetLength(FPermissionsStr,0); //初始化当前权限数组
//构造权限字符串数组,最大权限256个,目前是没有超过的
for i := 0 to 255 do
begin
Permission := TPermission(i);
if not (Permission in FPermissions) then continue;
PermissionStr := GetEnumName(typeInfo(TPermission), i);
if (PermissionStr = '') or (PermissionStr = 'uAndroid_Permissions_Component') then
Break;
//增加权限数组字符串
SetLength(FPermissionsStr,Length(FPermissionsStr) + 1);
FPermissionsStr[Length(FPermissionsStr) - 1] := Permission_Prefix + PermissionStr;
end;
//如果没有选择授权,则直接退出
if Length(FPermissionsStr) = 0 then Exit;
{$IFDEF DEBUG}
count := Length(FPermissionsStr);
S := '';
for i := 0 to count - 1 do
S := S + FPermissionsStr[i] + #13#10;
ShowMessage(S) ;
{$ENDIF}
//申请权限
PermissionsService.RequestPermissions
(FPermissionsStr, AndroidPermissionRequestResult,
DisplayRationale);
end;
constructor TAndroid_Permission.Create(AOwner: TComponent);
begin
inherited;
end;
destructor TAndroid_Permission.Destroy;
begin
inherited;
end;
procedure TAndroid_Permission.DisplayRationale(Sender: TObject;
const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);
var
I: Integer;
RationaleMsg: string;
begin
for I := 0 to High(APermissions) do
begin
if APermissions[I] = FPermissionsStr[i] then
RationaleMsg := RationaleMsg +
'App needs [' + FPermissionsStr[i] + '] Right' + SLineBreak +
SLineBreak;
end;
// Show an explanation to the user *asynchronously* - don't block this thread waiting for the user's response!
// After the user sees the explanation, invoke the post-rationale routine to request the permissions
TDialogService.ShowMessage(RationaleMsg,
procedure(const AResult: TModalResult)
begin
APostRationaleProc;
end)
end;
function TAndroid_Permission.IsPermissionGranted(APermission: string): Boolean;
begin
if Trim(APermission) = '' then Exit(False);
try
Result := PermissionsService.IsPermissionGranted(APermission);
except on E: Exception do
Result := False;
end;
end;
procedure TAndroid_Permission.SetFPermissions(value: TPermissions);
begin
FPermissions := value;
end;
end.
使用:
var Android_Permission : TAndroid_Permission;
procedure TGPS.DoShow; begin inherited; Android_Permission := TAndroid_Permission.Create(self); Android_Permission.Permissions := Android_Permission.Permissions + [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION]; Android_Permission.Apply; end;
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/18199146

浙公网安备 33010602011771号