web-dev-qa-db-ja.com

Androidマシュマロ:実行時に権限を変更するとアプリがクラッシュする

マシュマロは許可の取得を再設計しました。したがって、アクセス許可を必要とするメソッドを呼び出す前にアクセス許可を処理し、正常に機能しますが、次のシナリオでクラッシュします。

ステップ1:アプリを開き、必要なすべての権限を付与しました

ステップ2:[ホーム]ボタンをクリックしました(アプリはバックグラウンドにあります)

手順3:[設定]で権限を手動で変更する

ステップ4:マルチタスクからアプリを起動しましたが、アプリのコンテキストが無効になるためにクラッシュするようになりました

アプリが再度作成されるのを観察しましたが、なぜこれが発生するのか理解できません。この問題を修正するための提案は大歓迎です!

13
ABI

これは、マシュマロから追加された機能が原因です。実行時にユーザーにリクエストする必要があります。このために、私が作成したこのクラスを使用します。その後、必要な場所で使用してください

public class AppPermission {

    public static boolean isMarshmallowPlusDevice() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.Lollipop_MR1;
    }

    @TargetApi(Build.VERSION_CODES.M)
    public static boolean isPermissionRequestRequired(Activity activity, @NonNull String[] permissions, int requestCode) {
        if (isMarshmallowPlusDevice() && permissions.length > 0) {
            List<String> newPermissionList = new ArrayList<>();
            for (String permission : permissions) {
                if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) {
                    newPermissionList.add(permission);
                }
            }
            if (newPermissionList.size() > 0) {
                activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode);
                return true;
            }
        }
        return false;
    }
}

次に、ユーザーからの許可が必要な場所にこのコードを配置します。

if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]{"Android.permission.GET_ACCOUNTS"},
        REQUEST_APP_PERMISSION)) {
    // Your code if permission available
}

この後、FragmentまたはActivityにこのコードを入力します-

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_APP_PERMISSION:
            for (int i = 0; i < permissions.length; i++) {
                String permission = permissions[i];
                int grantResult = grantResults[i];
                switch (permission) {
                    case "Android.permission.GET_ACCOUNTS":
                        if (PackageManager.PERMISSION_GRANTED == grantResult) {
                            // Your code
                        }
                        break;
                }
            }
            break;
    }
}

上記のコードは、GET_ACCOUNTSのアクセス許可をリクエストするためのものです。必要に応じて変更できます。

1
Jimit Patel

最初にブール値を定義します

 private boolean isPermissionGranted = false;

次に、許可が付与されているかどうかを確認します。

if (!isPermissionGranted) {
        checkPermission();
    }

実行時のアクセス許可チェックの実際のコードは次のとおりです。

private void checkPermission() {
    int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA);
    int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            showMessage(getString(R.string.allow_access_to_camera_external_storage),
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                    REQUEST_CODE_ASK_PERMISSIONS);
                        }
                    });
            return;
        }
        ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                REQUEST_CODE_ASK_PERMISSIONS);
        return;
    } else {
        isPermissionGranted = true;
    }
}

private void showMessage(String message, DialogInterface.OnClickListener       listener) {
    new AlertDialog.Builder(UserProfile.this)
            .setMessage(message)
            .setPositiveButton(R.string.ok, listener)
            .setNegativeButton(R.string.cancel, null)
            .create()
            .show();
}

  @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_ASK_PERMISSIONS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                isPermissionGranted = true;

            } else {
                isPermissionGranted = false;
                Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT)
                        .show();
            }
            break;

        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

上記のコードから参照を取得して、アプリケーションに実装できます。

0
Riten

アプリが再度作成されるのを観察しましたが、なぜこれが発生するのか理解できません。この問題を修正するための提案は大歓迎です!

権限が変更されると、アプリケーションの「状態」を無効にする必要があるためです。これを行う適切な方法は、アプリケーション自体であるルートコンテキストを破棄することです。

これらの権限を必要とするAPIメソッドをクエリするたびに、権限が付与されているステータスを確認する必要があります。 "ユーザーがオンボーディングの権限を付与しました、わかりました、楽しんでください"を示すSharedPreferencesフラグを信頼することはできません。この点でアプリをステートレスにします。

たとえば、BaseActivity/BaseFragmentまたはUtilityを作成し、そこにすべてのチェックロジックを移動できます。

0
Drew