Разрешение среды выполнения Firemonkey android read_phone_state запрашивает получение 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;

person Dejan    schedule 27.09.2017    source источник
comment
кстати вы должны знать, что IMEI - это частные данные и, вероятно, скоро будет запрещен (как это уже есть на iphone)   -  person zeus    schedule 19.04.2018


Ответы (1)


РЕДАКТИРОВАТЬ: Извините, я не сделал еще немного домашней работы по 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
comment
спасибо за ваш ответ, было довольно ясно, но в Java здесь уже все работало нормально, проблема действительно в Delphi - person Márcio Rossato; 24.04.2018
comment
Вы используете Delphi XE6 (или более позднюю версию)? - person kris larson; 24.04.2018
comment
Да, токийская версия - person Márcio Rossato; 25.04.2018