Fragment#requestPermissions() でハマった

  • 36
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Android M から新しいパーミッションモデルになり、アプリから一部のパーミッションの権限を要求することが可能になりました。この実装を調べていてハマったところがあるので共有します。

パーミッション権限を要求するときは以下のような感じです。

公式には、 Activity#requestPermissions() を呼び出して、要求結果を Activity#onRequestPermissionsResult() で受け取る、と書いてあります。

if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant

    return;
}

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

                // permission was granted, yay! do the
                // calendar task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'switch' lines to check for other
        // permissions this app might request
    }
}

ハマったところ

1. Fragment にも requestPermissions() はある

@hotchemi のおかげで Fragment にも requestPermissions() が実装されてるのを知りました。公式を見る限り Activity だけにしか無いように見えるのつらい...

Android M Preview 版のソースコードを見ると、ちゃんと requestPermissions()onRequestPermissionsResult() が実装されていることが分かりました。

なので、安心して Fragment でパーミッション要求を実装できそうですね!!!!!!!!

package android.app;

public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {

    public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        Intent intent =
                mHost.getContext().getPackageManager().buildRequestPermissionsIntent(permissions);
        mHost.onStartActivityFromFragment(this, intent, requestCode, null);
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        /* callback - do nothing */
    }

2. Fragment に requestPermissions() はなかった

タイトル詐欺です。

Fragment に requestPermissions() があるとのことなので、満身創痍で App Permission のサンプルを実装していましたが、コード補完に requestPermissions() が候補リストに出てきませんでした!!!!!!!!!!!!!!!!

スクリーンショット 2015-06-29 16.46.34.png

「うーーーん......うーーーん......」と時間を無駄に消費したのですが、原因はすごく簡単に解決できるものでした。

まちがい

import android.support.v4.app.Fragment;

public class PermissionFragment extends Fragment {

    private void requestReadContactsPermission() {
        requestPermissions(
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    }

せいかい

import android.app.Fragment;

public class PermissionFragment extends Fragment {

    private void requestReadContactsPermission() {
        requestPermissions(
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    }

まとめ

現状はイカのどれかで対処する必要があります。

  • android.app.Fragment のほうを import する
  • support v4 のアップデートを待つ
  • Activity のほうで実装

無駄にハマった...

追記 7/13

support v4 のソースコードを見たら

    public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        /* callback - do nothing */
    }

    public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
        if (mHost != null) {
            return mHost.onShouldShowRequestPermissionRationale(permission);
        }
        return false;
    }

のように、ちゃんと実装されていました。なので、安心して v4 を使えますね。