РЕДАКТИРОВАТЬ: Извините, я не сделал еще немного домашней работы по FireMonkey. Это то, что я получаю за то, что сую голову в темы, где это неуместно. Я добавил этот контент, чтобы попытаться сделать мой ответ более достойным вознаграждения.
Если вы можете ограничить targetSdk
в манифесте приложения до 22 (5.1 Lollipop), то пользователь должен будет предоставить разрешение при установке, поэтому HasPermission
никогда не должно возвращать значение false. (Не знаю, как это работает с FireMonkey).
Если вы хотите использовать возможности динамических разрешений в Marshmallow+, вот некоторая информация, которую я почерпнул из эта страница:
Вам необходимо иметь доступ к методу обратного вызова Activity
onRequestPermissionsResult
. Вот все обручи, через которые вам придется перепрыгнуть:
- Используйте инструмент с открытым исходным кодом Dex2Jar, чтобы преобразовать файл Android
classes.dex
из Delphi обратно в Java, чтобы вы могли скомпилировать его для класса FMXNativeActivity
.
- Закодируйте подкласс
FMXNativeActivity
в Java, который определяет метод native
(давайте назовем его onRequestPermissionsResultNative
, а также переопределяет метод onRequestPermissionsResult
для вызова собственного метода.
- запустите
javac
, чтобы получить файл .class с вашим подклассом
- запустите
jar
, чтобы поместить файл .class в файл .jar
- запустите
dx.bat
, чтобы превратить ваш файл .jar в файл .dex для Android
- запустите
DexMerger
, чтобы объединить ваш файл .dex с файлом class.dex Delphi.
- Теперь все, что осталось сделать, это написать хитрый код Delphi, чтобы определить ваш метод
onRequestPermissionsResultNative
и зарегистрировать его в среде JNI. О, и не забудьте переключиться на правильный поток в вашем родном методе.
Ссылка, на которую я ссылался, показывает, как это сделать с помощью onActivityResult
. Вам придется адаптировать эти шаги для другого метода.
И я даже не говорил о том, как справиться с тем, как ОС приостанавливает ваше приложение, чтобы запросить разрешение у пользователя, и возобновляет его после.
Пусть это будет уроком для всех: не полагайтесь на кросс-платформенные инструменты; вы будете разочарованы.
Я работаю на Java, а не на Delphi, поэтому здесь вам придется немного экстраполировать.
Как и вы, мне нужно получить номер IMEI, и системный диалог запрашивает у пользователя что-то вроде: «Разрешить приложению совершать телефонные звонки и управлять ими?» Мне нужно объяснить пользователю, что это приложение просто получает идентификатор устройства и не собирается совершать или управлять телефонными звонками. Так
- Проверьте, есть ли у вас разрешение
- Если у вас нет разрешения, проверьте, следует ли отображать объяснение
- Если вам не нужно показывать объяснение, запустите операцию запроса разрешения
Я должен упомянуть, что shouldShowRequestPermissionRationale
и requestPermissions
являются методами класса Activity
.
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
, вам нужно переопределить метод onRequestPermissionsResult
Activity
:
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
}
}
}
По-видимому, когда система запрашивает у пользователя разрешение, она останавливает ваше приложение, поэтому вы не можете показать пользовательский интерфейс в этот момент, чтобы сообщить пользователю, что у вас нет разрешения. Поэтому я устанавливаю флаг, и когда приложение возобновляет работу, затем я сообщаю пользователю, что у приложения нет разрешения на выполнение операции.
@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()
возвращает true только после того, как пользователь один раз отклонил разрешение. Таким образом, вы еще не показываете пользователю пользовательский интерфейс с обоснованием.
- Приложение звонит
requestPermissions()
- Система спросит пользователя «Разрешить приложению совершать телефонные звонки и управлять ими?»
- Пользователь решает, что это WAAAAAAY слишком страшно, и нажимает кнопку «Нет».
onRequestPermissionsResult()
вызывается с отрицательным результатом, и устанавливается mPermissionDenied
.
onResumeFragments()
вызывается, и пользователю отображается диалоговое окно о том, что он не может получить бесплатную пробную версию, поскольку у приложения нет разрешения.
- Пользователь решает повторить попытку.
doPermissionsStuff()
называется.
- Приложение вызывает
checkSelfPermission()
и (снова) определяет, что разрешение еще не предоставлено
- Приложение вызывает
shouldShowRequestPermissionRationale()
. На этот раз он возвращает true.
- Приложение отображает успокаивающее и успокаивающее сообщение пользователю, что нет, мы не собираемся завладевать вашим телефоном, нам просто нужен чертов номер IMEI, вот и все, и если вы не разрешите приложению получить доступ к IMEI, у вас нет бесплатной пробной версии. Мне нужно провести линию где-то.
- Пользователь нажимает «Продолжить», поэтому флаг
mHasReadRationale
устанавливается в значение «истина» и метод doPermissionsStuff()
вызывается снова.
- Приложение вызывает
checkSelfPermission()
и знаете что? разрешение еще не предоставлено
- Поскольку флаг установлен, пользователь не получает пользовательский интерфейс с обоснованием.
- Приложение звонит
requestPermissions()
- Система спросит пользователя «Разрешить приложению совершать телефонные звонки и управлять ими?»
- Пользователь смиряется с судьбой и нажимает «Да».
onRequestPermissionsResult()
вызывается с предоставленным результатом, и регистрация бесплатной пробной версии продвигается вперед.
Вам также следует ознакомиться с образцом кода Google по адресу https://developer.android.com/samples/RuntimePermissions/index.html
person
kris larson
schedule
17.04.2018