Android 6.0 自定義權限

問題描述: 想在APP1中的Activity中發(fā)送一個廣播,在APP2中定義一個Receiver然后接收這個廣播,為了安全,這個廣播聲明了一個自定義權限。但是在6.x的系統(tǒng)上怎么都接收不到廣播。

APP2代碼如下

  1. 定義一個自定義的BroadcastReceiver用于接收廣播消息代碼如下:
public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("Q_M:", "成功接收廣播");
    }
}
  1. AndroidManifest.xml聲明自定義權限,靜態(tài)注冊MyReceiver
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.febsky.myapplication">

     <!-- 權限聲明 注意最后兩行-->
    <permission
        android:name="me.febsky.PPPP"
        android:label="@string/app_name"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="dangerous"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 靜態(tài)注冊 -->
        <receiver
            android:name=".MyReceiver"
            android:permission="me.febsky.PERMISSION">
            <intent-filter>
                <action android:name="me.febsky.ACTION" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

APP1 的主界面就一個Button,功能是發(fā)送廣播,不再給出。

  1. button的點擊事件如下:
   private static final String ACTION = "me.febsky.ACTION";

    //button的點擊事件
    public void onClick(View view) {

        Intent intent = new Intent(ACTION);
        // 發(fā)送廣播
        sendBroadcast(intent);
    }
  1. AndroidManifest.xml聲明使用權限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.febsky.aidltest">

    <!-- 權限使用聲明 -->
    <uses-permission android:name="me.febsky.PERMISSION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

注意這兩個APP的啟動順序,先啟動APP2,然后啟動APP1

到這里為止,其實兩個APP之間已經(jīng)可以通信了(6.0以下的手機)。為什么6.0以上的手機不行,這就涉及到一個問題,【運行時權限】。

Android6.0 運行時權限

對于6.0以下的權限及在安裝的時候,根據(jù)權限聲明產(chǎn)生一個權限列表,用戶只有在同意之后才能完成app的安裝,造成了我們想要使用某個app,就要默默忍受其一些不必要的權限(比如是個app都要訪問通訊錄、短信等)。而在6.0以后,我們可以直接安裝,當app需要我們授予不恰當?shù)臋嘞薜臅r候,我們可以予以拒絕(比如:單機的象棋對戰(zhàn),請求訪問任何權限,我都是不同意的)。當然你也可以在設置界面對每個app的權限進行查看,以及對單個權限進行授權或者解除授權。

系統(tǒng)權限分為兩類:正常權限和危險權限:

  • 正常權限Normal Permissions不會直接給用戶隱私權帶來風險。如果您的應用在其清單中列出了正常權限,系統(tǒng)將自動授予該權限。
  • 危險權限會授予應用訪問用戶機密數(shù)據(jù)的權限。如果您的應用在其清單中列出了正常權限,系統(tǒng)將自動授予該權限。如果您列出了危險權限,則用戶必須明確批準您的應用使用這些權限。

Dangerous Permission,是按照權限組分配使用的。如果app運行在Android 6.x的機器上,對于授權機制是這樣的。如果你申請某個危險的權限,假設你的app早已被用戶授權了同一組的某個危險權限,那么系統(tǒng)會立即授權,而不需要用戶去點擊授權。比如你的app對READ_CONTACTS已經(jīng)授權了,當你的app申請WRITE_CONTACTS時,系統(tǒng)會直接授權通過。此外,對于申請時彈出的dialog上面的文本說明也是對整個權限組的說明,而不是單個權限(ps:這個dialog是不能進行定制的)。

任何權限都可屬于一個權限組,包括正常權限和應用定義的權限。但權限組僅當權限危險時才影響用戶體驗。可以忽略正常權限的權限組。

根據(jù)上面的介紹,我們又兩種解決方式

  1. 聲明權限為Normal Permissions,也就是在(APP2中的AndroidManifest.xml)聲明權限的時候
     <!-- 權限聲明 最后一行-->
    <permission
        android:name="me.febsky.PPPP"
        android:label="@string/app_name"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="normal"/>
  1. 在運行時檢查是否獲得了這個自定義的dangerous權限,如果沒有那么動態(tài)申請一個。如何動態(tài)申請權限
    這時候要改造下發(fā)起廣播的app中代碼(APP1)
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClick(View view) {
        if (ContextCompat.checkSelfPermission(this, p) == PackageManager.PERMISSION_GRANTED) {
            sendBroadCast();
        } else {
            ActivityCompat.requestPermissions(this, new String[]{p}, 11);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 11) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                sendBroadCast();
            } else {
                Toast.makeText(this, "未授權!", Toast.LENGTH_LONG).show();
            }
        }
    }

    private static final String p = "me.febsky. PERMISSION";
    private static final String ACTION = "me.febsky.ACTION";

    private void sendBroadCast() {

        Intent shortcut = new Intent(ACTION);
        // 發(fā)送廣播
        sendBroadcast(shortcut);
    }
}

注:羅里吧嗦的說了這么多廢話,其實就是一點,如果在Android6.0上聲明的自定義權限的level是dangerous的,那么在使用這個自定義的權限的app中要動態(tài)的申請這個權限。(也就是要彈出一個請求授權的Dialog,讓用戶來授權)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容