運行時權限申請

參考官方鏈接

并沒有測試所有機型价淌,官方 ROM 和 小米是 ok 的业踏。
針對:
1. 權限首次申請
2. 被拒絕后的申請
3. Don't ask again 勾選后的申請
三種情形的申請方案。

1. 檢查權限

ContextCompat.checkSelfPermission()
e.g. 請求日歷的寫入權限

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);
// permissionCheck 為 PackageManager.PERMISSION_GRANTED 或 PERMISSION_DENIED 

2. 請求權限

2.1 解釋應用為什么需要權限

ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)
如果請求的權限用戶已經(jīng)拒絕過灌灾,但沒有點擊 “Don't ask again”,就會返回 true卖毁,表示需要顯示 權限請求解釋提示
如果用戶點擊了 Don't ask again羡藐,是返回 false 的贩毕,還需要配合權限檢查為 DENIED,才說明該權限 為 Don't ask again

2.2 請求權限

ActivityCompat.requestPermissions(Activity activity, String[] permissions,int requestCode);

e.g.

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {

    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {

        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.
    } else {
        // No explanation needed, we can request the permission.
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
}

3. 處理權限請求響應

通過onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)方法來判斷權限請求的結果
形參中 permissionsgrantResults 是一一對應的仆嗦,被拒絕的權限可以通過shouldShowRequestPermissionRationale方法來判斷是否為 Dont ask again 從而提示用戶手動前往應用設置頁開啟

e.g.

@Override
public void onRequestPermissionsResult(int requestCode,
        String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }
        // other 'case' lines to check for other
        // permissions this app might request
    }
}



附1:一個簡單的 demo

/**
 * <pre>
 *     @author Jiun
 *     @date  :2018/09/05/18:58
 *     desc   : 文件描述
 *     version: 當前版本號
 * </pre>
 */
public class PermissionHandler {
    private static final int REQ_CODE = 0x10;
    private WeakReference<Activity> mActivityWeakReference;
    private static final String[] CAMERA = new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    private String[] mPermissionArrRequest;
    /**
     * 可用來記錄最新申請的權限辉阶,進行更細致的判斷處理,暫時未用到
     */
    private String mPermissionLatestRequest;

    private PermissionHandler(Activity activity, @NonNull String[] permissions) {
        mActivityWeakReference = new WeakReference<>(activity);
        mPermissionArrRequest = permissions;
        mPermissionLatestRequest = "";
    }

    public static PermissionHandler getInstance(Activity activity, String[] permissions) {
        return new PermissionHandler(activity, permissions);
    }

    public static PermissionHandler getCameraInstance(Activity activity) {
        return new PermissionHandler(activity, CAMERA);
    }

    public boolean checkPermission() {
        final Activity activity = mActivityWeakReference.get();
        if (activity == null) {
            return false;
        }
        for (String permission : mPermissionArrRequest) {
            mPermissionLatestRequest = permission;
            if (isNotGranted(activity, permission)) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                    DialogUtil.showConfirmDialog(activity, "請授權下面的權限申請瘩扼,否則該功能可能無法使用", new DialogUtil.OnDialogConfirmClickListener() {
                        @Override
                        public void onConfirm(Dialog dialog) {
                            ActivityCompat.requestPermissions(activity, mPermissionArrRequest, REQ_CODE);
                            dialog.cancel();
                        }
                    }).show();
                } else {
                    ActivityCompat.requestPermissions(activity, mPermissionArrRequest, REQ_CODE);
                }
                return false;
            }
        }
        return true;
    }

    /**
     * 需要在 Activity#onRequestPermissionResult() 中調用此方法
     */
    public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQ_CODE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0) {
                    for (int i = 0; i < grantResults.length; i++) {
                        int grantResult = grantResults[i];
                        if (grantResult == PackageManager.PERMISSION_GRANTED) {
                            // TODO(Hjy): 2018/9/5 授權成功谆甜,比如說 在 checkPermission 中把未授權的權限保存起來,在授權結果中進行比對集绰,看是否全部授權成功规辱,來設置授權的回調
                        } else if (permissions.length > i) {
                            if (checkIsDeniedForeverAndShowDialog(permissions[i])) {
                                return;
                            }
                        }
                    }
                } else {
                    for (String permission : permissions) {
                        if (checkIsDeniedForeverAndShowDialog(permission)) {
                            return;
                        }
                    }
                }
                return;
            }
            default:
        }
    }

    private boolean checkIsDeniedForeverAndShowDialog(String permission) {
        final Activity activity = mActivityWeakReference.get();
        if (activity == null) {
            return true;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && isDeniedForever(activity, permission)) {
            DialogUtil.showCommonDialog(activity, "權限申請失敗或被拒絕,請手動前往授權", new DialogUtil.OnDialogConfirmClickListener() {
                @Override
                public void onConfirm(Dialog dialog) {
                    dialog.dismiss();
                    startAppDetailsSettings(activity);
                }
            }).show();
            return true;
        }
        return false;
    }

    private boolean isNotGranted(Activity activity, String permission) {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(activity, permission);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private boolean isDeniedForever(Activity activity, String permission) {
        return isNotGranted(activity, permission) && !activity.shouldShowRequestPermissionRationale(permission);
    }

    /**
     * 打開系統(tǒng)設置界面
     */
    private void startAppDetailsSettings(Activity activity) {
        Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
        intent.setData(Uri.parse("package:" + activity.getPackageName()));
        ComponentName componentName = intent.resolveActivity(activity.getPackageManager());
        if (componentName != null) {
            activity.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
        }
    }
}

使用步驟(請求相機用到的權限為例):

  1. 在合適的地方獲取實例
PermissionHandler mPermissionHandler = PermissionHandler.getCameraInstance(activity);
  1. 權限檢查并請求
if (mPermissionHandler.checkPermission()) {
  // 打開相機拍照
}
  1. 獲取 權限請求回調結果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (mPermissionHandler != null) {
        mPermissionHandler.onRequestPermissionResult(requestCode, permissions, grantResults);
    }
}

附2:危險權限和權限組

權限組 權限
CALENDAR READ_CALENDAR
WRITE_CALENDAR
CAMERA CAMERA
CONTACTS READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS`
LOCATION ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION`
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

附3:如何區(qū)分 i.e. 和 e.g.

上學的時候就很好奇栽燕,終于想起來搜搜了:joy:

1. 理解含義:
"i.e."是拉丁語 id est 的縮寫罕袋,意為"that is"(即), "e.g." 是拉丁語exempli gratia 的縮寫碍岔,意為"for the sake of example"(如例子)浴讯。

2. 把用法和好記的短語聯(lián)系起來:
記拉丁語可能比較難,就把"i.e."記為 "in essence"(本質上)蔼啦、 "in other words"(換句話)榆纽, "e.g." 記成 "example given"(給出例子) 。

3. 使用"i.e."來作解釋:
"i.e." 是用來在一句話之后換種方式解釋或描述之前說的內容捏肢。
The elephant is a pachyderm, i.e., an animal with thick skin and nails resembling hooves.(大象是厚皮類動物奈籽,即皮膚厚、有蹄子的動物)
I went to my least favorite place (i.e., the dentist).(我去我最喜歡的地方了鸵赫,即牙醫(yī)診所)

4. 注意:
"i.e."之后一般的是延伸的定義衣屏,也可以是個比喻。如果你把 "i.e." 替換為 "in other words"句子就通順奉瘤,如果是 "for example" 就不行了。

5. 試著把簡寫換成原意煮甥,聽起來通順的話就可能用對了:
比如 "I like quiet activities (e.g., reading)"(我喜歡安靜的活動(例如閱讀))盗温, "I like quiet activities (for example, reading)". 如果使用 i.e.,則用 "in other words"比 "that is."更好用成肘。

6. 在一個或多個例子前使用 "e.g." 想想 "e.g."后面要接的東西作為一個類別卖局, 然后看看這個類別里可以放什么東西:
Buy some vegetables, e.g., carrots.(買點蔬菜,比如胡蘿卜)
I like power metal (e.g., Firewind, Iced Earth, Sonata Arctica).(我喜歡能量金屬樂双霍,例如焚風樂隊砚偶、冰封大地樂隊批销、極光奏鳴曲樂團)
注意這里"i.e."說出來不通順。 "Carrots"(胡蘿卜)不是所有的蔬菜染坯,而只是一種而已均芽。如果要用 "i.e.",你可以說 "Buy some vegetables, i.e., the edible part of any plant."(買點蔬菜单鹿,即植物可食部分)同樣地掀宋,樂隊名也只是樂曲分格的一部分,如果要用 "i.e." 則"I like power metal, i.e., fast metal with symphonic elements and epic themes."(我喜歡能量金屬樂仲锄,即快速金屬樂搭配交響樂元素和史詩主題的樂曲風格)

7. 兩者都用括號或逗號:
要指示分開的從句劲妙,可以前面加個逗號,或者用括號括起來儒喊,兩者上述例子都用到镣奋。如果用括號要在兩個縮寫前就用上,寫出相應的例子或解釋以后把括號關上怀愧。

美式英語中侨颈,在 "i.e."、 "e.g."后加個逗號掸驱,英式則不用加肛搬。

小提示

  • 還是擔心用法用錯,則最好不用它們毕贼,甚至寫作中也不用温赔。你要表示“例如”時,就寫“for example”鬼癣,表示“即”的時候陶贼,用“that is”。這樣也不會多寫多少待秃,也不出錯拜秧。
  • 更好的"i.e." 和 "e.g."對比的例子,就是 Chili Palmer (John Travolta) 和Ray "Bones" Barboni (Dennis Farina)在 1995 電影 Get Shorty (《黑道當家》)里的對白
  • 沒必要在"e.g." 后的一長串行表中使用 "etc." 章郁,因為"e.g." 本身就表示不完整的列表参淫。
  • 說話的時候最好不用"i.e." 、 "e.g." 崭倘,而說"that is" 祥楣、 "in other words" 代表"i.e." , "for example" 培廓、 "for instance" 代表 "e.g."
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末惹悄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肩钠,更是在濱河造成了極大的恐慌泣港,老刑警劉巖暂殖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異当纱,居然都是意外死亡呛每,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門惫东,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莉给,“玉大人,你說我怎么就攤上這事廉沮⊥嵌簦” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵滞时,是天一觀的道長叁幢。 經(jīng)常有香客問我,道長坪稽,這世上最難降的妖魔是什么曼玩? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮窒百,結果婚禮上黍判,老公的妹妹穿的比我還像新娘。我一直安慰自己篙梢,他們只是感情好顷帖,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著渤滞,像睡著了一般贬墩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妄呕,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天陶舞,我揣著相機與錄音,去河邊找鬼绪励。 笑死肿孵,一個胖子當著我的面吹牛,可吹牛的內容都是我干的疏魏。 我是一名探鬼主播停做,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蠢护!你這毒婦竟也來了雅宾?” 一聲冷哼從身側響起养涮,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤葵硕,失蹤者是張志新(化名)和其女友劉穎眉抬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懈凹,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蜀变,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了介评。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片库北。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖们陆,靈堂內的尸體忽然破棺而出寒瓦,到底是詐尸還是另有隱情,我是刑警寧澤坪仇,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布杂腰,位于F島的核電站,受9級特大地震影響椅文,放射性物質發(fā)生泄漏喂很。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一皆刺、第九天 我趴在偏房一處隱蔽的房頂上張望少辣。 院中可真熱鬧,春花似錦羡蛾、人聲如沸漓帅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽煎殷。三九已至,卻和暖如春腿箩,著一層夾襖步出監(jiān)牢的瞬間豪直,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工珠移, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弓乙,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓钧惧,卻偏偏與公主長得像暇韧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浓瞪,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容

  • 我在android6.0運行權限上的處理是懈玻,在一個類中寫權限的申請,在需要權限的類中去繼承乾颁,達到權限申請效果涂乌。 1...
    吃貨養(yǎng)成記閱讀 340評論 1 1
  • 1.簡介 在Android6.0之前版本艺栈,權限請求較為簡單,僅在用戶安裝app時將自己需要使用的所有權限列出來告知...
    空_歡喜閱讀 953評論 2 15
  • 一湾盒、引言 隨著Android6.0發(fā)布湿右,系統(tǒng)增加了一些新的特性和功能。這次的發(fā)布介紹了一種新的權限機制罚勾。用戶可以在...
    宇是我閱讀 7,419評論 7 41
  • 1. Android 6.0 在運行時請求權限介紹 從 Android 6.0(API 級別 23)開始毅人,用戶開始...
    conio閱讀 4,215評論 0 6
  • (一) 自參加父母課程后,對李老師講到的很多知識點特別喜歡尖殃,比如“人的三種原始能量如何自由轉換”“如何做體驗者”“...
    藍溪碧潭閱讀 225評論 1 2