Firemonkey android read_phone_state 运行时权限要求获取 IMEI
Firemonkey android read_phone_state runtime permission asks to get IMEI
如何在运行时获取read_phone_state权限获取IMEI号?
if not HasPermission('android.permission.READ_PHONE_STATE') then
begin
//ASK AND GET PERMISSION ?
end;
function TForm1.HasPermission(const Permission: string): Boolean;
begin
//Permissions listed at http://d.android.com/reference/android/Manifest.permission.html
{$IF RTLVersion >= 30}
Result := TAndroidHelper.Context.checkCallingOrSelfPermission(
{$ELSE}
Result := SharedActivityContext.checkCallingOrSelfPermission(
{$ENDIF}
StringToJString(Permission)) =
TJPackageManager.JavaClass.PERMISSION_GRANTED;
end;
编辑:抱歉,我没有在 FireMonkey 上做更多的功课。这就是我将头伸向不属于它的话题所得到的。我添加此内容是为了让我的回答更值得赏金。
如果您可以将应用程序清单上的 targetSdk
限制为 22 (5.1 Lollipop),则用户必须授予安装权限,因此 HasPermission
永远不会 return false . (不确定它如何与 FireMonkey 一起使用)。
如果您想在 Marshmallow+ 中使用动态权限功能,这里是我从 this page 中收集到的一些信息:
您需要有权访问 Activity
回调方法 onRequestPermissionsResult
。这是您必须跳过的所有障碍:
- 使用开源工具 Dex2Jar 将 Android
classes.dex
文件从 Delphi 转换回 Java 这样你就可以针对 FMXNativeActivity
class.
- 在 Java 中编写一个
FMXNativeActivity
的子 class,它定义了一个 native
方法(我们称它为 onRequestPermissionsResultNative
并重写 onRequestPermissionsResult
方法调用本机方法。
- 运行
javac
用你的子class 得到一个 .class 文件
- 运行
jar
将 .class 文件放入 .jar 文件
- 运行
dx.bat
将您的 .jar 文件转换为 Android .dex 文件
- 运行
DexMerger
将您的 .dex 文件合并到 Delphi 的 classes.dex 文件中
- 现在剩下要做的就是编写一些棘手的 Delphi 代码来定义您的
onRequestPermissionsResultNative
方法并将其注册到 JNI 环境。哦,别忘了在您的本机方法中切换到正确的线程。
我引用的 link 显示了如何使用 onActivityResult
执行此操作。您必须针对其他方法调整这些步骤。
我什至还没有谈到如何处理 OS 暂停您的应用程序以请求用户许可并在之后恢复它。
让这成为所有人的教训:不要相信跨平台工具;你会失望的。
我在Java而不是Delphi工作,所以你必须在这里稍微推断一下。
像你一样,我必须获取 IMEI 号码,系统对话框会询问用户类似的内容:"Allow app to make and manage phone calls?"我需要向用户解释该应用程序只是获取设备 ID 而不是不会拨打或管理 phone 电话。所以
- 检查是否有权限
- 如果您没有权限,请检查是否应显示说明
- 如果不需要显示说明,则开始权限请求操作
我应该提到 shouldShowRequestPermissionRationale
和 requestPermissions
是 Activity
class 上的方法。
private static final int READ_PHONE_STATE_PERMISSIONS_REQUEST = 2;
private boolean mHasReadRationale;
void doPermissionsStuff() {
// version checking code omitted, this block runs for marshmallow and later
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
// do the operation that needs the permission here
} else {
// the flag indicates if the rationale dialog has already been displayed
if (! mHasReadRationale && shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) {
// pop a dialog that explains what's going on to the user
} else {
requestPermissions(new String[] {Manifest.permission.READ_PHONE_STATE}, READ_PHONE_STATE_PERMISSIONS_REQUEST);
}
}
}
在此对话框的肯定按钮中(即用户想要继续)将 mHasReadRationale
标志设置为 true 并再次调用 doPermissionsStuff
。 (对于取消,我将用户返回到上一个屏幕。)
为了获得 requestPermissions
操作的结果,您需要覆盖 Activity
的 onRequestPermissionsResult
方法:
private boolean mPermissionDenied;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case READ_PHONE_STATE_PERMISSIONS_REQUEST:
// I'm only checking for one permission, so I make assumptions here
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// you can do the operation that needs the permission now
} else {
mPermissionDenied = true; // set a flag for checking later
}
}
}
显然,当系统向用户请求权限时,它会停止您的应用程序,因此此时您不能显示 UI 来告诉用户您没有权限。所以我设置了一个标志,当应用程序恢复时,然后我告诉用户该应用程序没有执行该操作的权限。
@Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mPermissionDenied) {
// show dialog to the user that the app can't do the operation because it doesn't have permission
mPermissionDenied = false;
}
}
下面是一个示例流程:
- 用户想要免费试用,而应用需要获取 IMEI,这样他们就无法一次又一次地获得免费试用,天哪。应用调用
doPermissionsStuff()
.
- 应用程序调用
checkSelfPermission()
并确定尚未授予权限
- 应用调用
shouldShowRequestPermissionRationale()
。根据我的经验,shouldShowRequestPermissionRationale()
只有在用户拒绝一次权限后才 return 为真。所以你还没有向用户显示基本原理 UI。
- 应用调用
requestPermissions()
- 系统会询问用户"Allow application to make and manage phone calls?"
- 用户认为这太可怕了,按下了否按钮。
使用拒绝结果调用 onRequestPermissionsResult()
并设置 mPermissionDenied
。
onResumeFragments()
被调用并向用户显示一个对话框,提示他们无法获得免费试用,因为该应用没有权限。
- 用户决定重试。
doPermissionsStuff()
被调用。
- 应用程序调用
checkSelfPermission()
并(再次)确定尚未授予权限
- 应用调用
shouldShowRequestPermissionRationale()
。这次 return 是真的。
- 应用程序向用户显示一条平静和舒缓的消息,不,我们不会接管您的 phone,我们只想要该死的 IMEI 号码,仅此而已,如果您不这样做如果不允许该应用访问 IMEI,您将无法免费试用。我必须在某处画线 .
- 用户按下继续键,因此
mHasReadRationale
标志设置为 true 并再次调用 doPermissionsStuff()
方法。
- 应用程序调用
checkSelfPermission()
并且 - 你猜怎么着?尚未授予权限
- 由于设置了标志,用户不明白原因 UI。
- 应用调用
requestPermissions()
- 系统会询问用户"Allow application to make and manage phone calls?"
- 用户听天由命并按是。
onRequestPermissionsResult()
以授予的结果调用,免费试用注册继续进行。
您还应该在 https://developer.android.com/samples/RuntimePermissions/index.html
查看 Google 的示例代码
如何在运行时获取read_phone_state权限获取IMEI号?
if not HasPermission('android.permission.READ_PHONE_STATE') then
begin
//ASK AND GET PERMISSION ?
end;
function TForm1.HasPermission(const Permission: string): Boolean;
begin
//Permissions listed at http://d.android.com/reference/android/Manifest.permission.html
{$IF RTLVersion >= 30}
Result := TAndroidHelper.Context.checkCallingOrSelfPermission(
{$ELSE}
Result := SharedActivityContext.checkCallingOrSelfPermission(
{$ENDIF}
StringToJString(Permission)) =
TJPackageManager.JavaClass.PERMISSION_GRANTED;
end;
编辑:抱歉,我没有在 FireMonkey 上做更多的功课。这就是我将头伸向不属于它的话题所得到的。我添加此内容是为了让我的回答更值得赏金。
如果您可以将应用程序清单上的 targetSdk
限制为 22 (5.1 Lollipop),则用户必须授予安装权限,因此 HasPermission
永远不会 return false . (不确定它如何与 FireMonkey 一起使用)。
如果您想在 Marshmallow+ 中使用动态权限功能,这里是我从 this page 中收集到的一些信息:
您需要有权访问 Activity
回调方法 onRequestPermissionsResult
。这是您必须跳过的所有障碍:
- 使用开源工具 Dex2Jar 将 Android
classes.dex
文件从 Delphi 转换回 Java 这样你就可以针对FMXNativeActivity
class. - 在 Java 中编写一个
FMXNativeActivity
的子 class,它定义了一个native
方法(我们称它为onRequestPermissionsResultNative
并重写onRequestPermissionsResult
方法调用本机方法。 - 运行
javac
用你的子class 得到一个 .class 文件
- 运行
jar
将 .class 文件放入 .jar 文件 - 运行
dx.bat
将您的 .jar 文件转换为 Android .dex 文件 - 运行
DexMerger
将您的 .dex 文件合并到 Delphi 的 classes.dex 文件中 - 现在剩下要做的就是编写一些棘手的 Delphi 代码来定义您的
onRequestPermissionsResultNative
方法并将其注册到 JNI 环境。哦,别忘了在您的本机方法中切换到正确的线程。
我引用的 link 显示了如何使用 onActivityResult
执行此操作。您必须针对其他方法调整这些步骤。
我什至还没有谈到如何处理 OS 暂停您的应用程序以请求用户许可并在之后恢复它。
让这成为所有人的教训:不要相信跨平台工具;你会失望的。
我在Java而不是Delphi工作,所以你必须在这里稍微推断一下。
像你一样,我必须获取 IMEI 号码,系统对话框会询问用户类似的内容:"Allow app to make and manage phone calls?"我需要向用户解释该应用程序只是获取设备 ID 而不是不会拨打或管理 phone 电话。所以
- 检查是否有权限
- 如果您没有权限,请检查是否应显示说明
- 如果不需要显示说明,则开始权限请求操作
我应该提到 shouldShowRequestPermissionRationale
和 requestPermissions
是 Activity
class 上的方法。
private static final int READ_PHONE_STATE_PERMISSIONS_REQUEST = 2;
private boolean mHasReadRationale;
void doPermissionsStuff() {
// version checking code omitted, this block runs for marshmallow and later
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
// do the operation that needs the permission here
} else {
// the flag indicates if the rationale dialog has already been displayed
if (! mHasReadRationale && shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) {
// pop a dialog that explains what's going on to the user
} else {
requestPermissions(new String[] {Manifest.permission.READ_PHONE_STATE}, READ_PHONE_STATE_PERMISSIONS_REQUEST);
}
}
}
在此对话框的肯定按钮中(即用户想要继续)将 mHasReadRationale
标志设置为 true 并再次调用 doPermissionsStuff
。 (对于取消,我将用户返回到上一个屏幕。)
为了获得 requestPermissions
操作的结果,您需要覆盖 Activity
的 onRequestPermissionsResult
方法:
private boolean mPermissionDenied;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case READ_PHONE_STATE_PERMISSIONS_REQUEST:
// I'm only checking for one permission, so I make assumptions here
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// you can do the operation that needs the permission now
} else {
mPermissionDenied = true; // set a flag for checking later
}
}
}
显然,当系统向用户请求权限时,它会停止您的应用程序,因此此时您不能显示 UI 来告诉用户您没有权限。所以我设置了一个标志,当应用程序恢复时,然后我告诉用户该应用程序没有执行该操作的权限。
@Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mPermissionDenied) {
// show dialog to the user that the app can't do the operation because it doesn't have permission
mPermissionDenied = false;
}
}
下面是一个示例流程:
- 用户想要免费试用,而应用需要获取 IMEI,这样他们就无法一次又一次地获得免费试用,天哪。应用调用
doPermissionsStuff()
. - 应用程序调用
checkSelfPermission()
并确定尚未授予权限 - 应用调用
shouldShowRequestPermissionRationale()
。根据我的经验,shouldShowRequestPermissionRationale()
只有在用户拒绝一次权限后才 return 为真。所以你还没有向用户显示基本原理 UI。 - 应用调用
requestPermissions()
- 系统会询问用户"Allow application to make and manage phone calls?"
- 用户认为这太可怕了,按下了否按钮。 使用拒绝结果调用
onRequestPermissionsResult()
并设置mPermissionDenied
。onResumeFragments()
被调用并向用户显示一个对话框,提示他们无法获得免费试用,因为该应用没有权限。- 用户决定重试。
doPermissionsStuff()
被调用。 - 应用程序调用
checkSelfPermission()
并(再次)确定尚未授予权限 - 应用调用
shouldShowRequestPermissionRationale()
。这次 return 是真的。 - 应用程序向用户显示一条平静和舒缓的消息,不,我们不会接管您的 phone,我们只想要该死的 IMEI 号码,仅此而已,如果您不这样做如果不允许该应用访问 IMEI,您将无法免费试用。我必须在某处画线 .
- 用户按下继续键,因此
mHasReadRationale
标志设置为 true 并再次调用doPermissionsStuff()
方法。 - 应用程序调用
checkSelfPermission()
并且 - 你猜怎么着?尚未授予权限 - 由于设置了标志,用户不明白原因 UI。
- 应用调用
requestPermissions()
- 系统会询问用户"Allow application to make and manage phone calls?"
- 用户听天由命并按是。
onRequestPermissionsResult()
以授予的结果调用,免费试用注册继续进行。
您还应该在 https://developer.android.com/samples/RuntimePermissions/index.html
查看 Google 的示例代码