孔记 發表於 2024-5-18 11:00:00

delphi安卓动态权限申请

<p>delphi安卓动态权限申请</p>
<p>安卓8及以上版本,除了原来的静态权限申请以外,还需要动态权限申请。</p>
<p>delphi10.3开始支持安卓动态权限申请。</p>
<p>delphi11开始官方改变了安卓动态权限申请的参数类型,导致原来编写的代码,编码报错。</p>
<p>下面的代码,可以很好地解决权限问题。兼顾了delphi10.3和delphi11以后版本。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">{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&lt;string&gt;)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&lt;string&gt;;
    procedure SetFPermissions(value: TPermissions);
    // **** 关于 Android 权限相关 ****
    procedure DisplayRationale(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);

{$IF CompilerVersion &gt;= 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&lt;string&gt;;
      const AGrantResults: TArray&lt;TPermissionStatus&gt;);
{$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', );
//end;

{ TAndroid_Permission }

{$IF CompilerVersion &gt;= 35.0}
procedure TAndroid_Permission.AndroidPermissionRequestResult(Sender: TObject;
const APermissions: TClassicStringDynArray;
const AGrantResults: TClassicPermissionStatusDynArray);
var
i,count : integer;
NoGranteds : TArray&lt;string&gt;;
begin
// 判断是否申请的授权都已经批准
SetLength(NoGranteds,0);
count := Length(FPermissionsStr);

for i := 0 to count - 1 do    //逐条判断是否已经成功授权
    begin
    {$IFDEF DEBUG}
      showmessage(GetEnumName(typeInfo(TPermissionStatus), Ord(AGrantResults)) + ' : '#13#10 + FPermissionsStr);
    {$ENDIF}
    if AGrantResults &lt;&gt; TPermissionStatus.Granted then
       begin
         SetLength(NoGranteds,Length(NoGranteds) + 1);
         NoGranteds := FPermissionsStr;
       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&lt;string&gt;;
      const AGrantResults: TArray&lt;TPermissionStatus&gt;);
var
i,count : integer;
NoGranteds : TArray&lt;string&gt;;
begin
// 判断是否申请的授权都已经批准
SetLength(NoGranteds,0);
count := Length(FPermissionsStr);

for i := 0 to count - 1 do    //逐条判断是否已经成功授权
    begin
    if AGrantResults &lt;&gt; TPermissionStatus.Granted then
       begin
         SetLength(NoGranteds,Length(NoGranteds) + 1);
         NoGranteds := FPermissionsStr;
       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 &lt; 33.0}   //10.3 Rio
    Exit;//10.3 以下不支持
{$ELSE}
   if (TOSVersion.Major &lt;= 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 := 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 + #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 = FPermissionsStr then
      RationaleMsg := RationaleMsg +
      'App needs [' + FPermissionsStr + '] 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.
</pre>
</div>
<p> 使用:</p>
<p>var Android_Permission : TAndroid_Permission;</p>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">procedure TGPS.DoShow;
begin
inherited;
Android_Permission := TAndroid_Permission.Create(self);
Android_Permission.Permissions := Android_Permission.Permissions + ;
Android_Permission.Apply;
end;
</pre>
</div>
<p>  </p>
<p> </p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/p/18199146</p><br><br>
来源:https://www.cnblogs.com/hnxxcxg/p/18199146
頁: [1]
查看完整版本: delphi安卓动态权限申请