問題描述: 想在APP1中的Activity中發(fā)送一個廣播蛤育,在APP2中定義一個Receiver然后接收這個廣播,為了安全,這個廣播聲明了一個自定義權(quán)限。但是在6.x的系統(tǒng)上怎么都接收不到廣播晨继。
APP2代碼如下
- 定義一個自定義的
BroadcastReceiver
用于接收廣播消息代碼如下:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("Q_M:", "成功接收廣播");
}
}
-
AndroidManifest.xml
聲明自定義權(quán)限,靜態(tài)注冊MyReceiver
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.febsky.myapplication">
<!-- 權(quán)限聲明 注意最后兩行-->
<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ā)送廣播紊扬,不再給出。
- button的點擊事件如下:
private static final String ACTION = "me.febsky.ACTION";
//button的點擊事件
public void onClick(View view) {
Intent intent = new Intent(ACTION);
// 發(fā)送廣播
sendBroadcast(intent);
}
-
AndroidManifest.xml
聲明使用權(quán)限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.febsky.aidltest">
<!-- 權(quán)限使用聲明 -->
<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以上的手機不行腹缩,這就涉及到一個問題,【運行時權(quán)限】空扎。
Android6.0 運行時權(quán)限
對于6.0以下的權(quán)限及在安裝的時候藏鹊,根據(jù)權(quán)限聲明產(chǎn)生一個權(quán)限列表,用戶只有在同意之后才能完成app的安裝勺卢,造成了我們想要使用某個app伙判,就要默默忍受其一些不必要的權(quán)限(比如是個app都要訪問通訊錄象对、短信等)黑忱。而在6.0以后,我們可以直接安裝勒魔,當app需要我們授予不恰當?shù)臋?quán)限的時候甫煞,我們可以予以拒絕(比如:單機的象棋對戰(zhàn),請求訪問任何權(quán)限冠绢,我都是不同意的)抚吠。當然你也可以在設(shè)置界面對每個app的權(quán)限進行查看,以及對單個權(quán)限進行授權(quán)或者解除授權(quán)弟胀。
系統(tǒng)權(quán)限分為兩類:正常權(quán)限和危險權(quán)限:
- 正常權(quán)限Normal Permissions不會直接給用戶隱私權(quán)帶來風險楷力。如果您的應用在其清單中列出了正常權(quán)限,系統(tǒng)將自動授予該權(quán)限孵户。
- 危險權(quán)限會授予應用訪問用戶機密數(shù)據(jù)的權(quán)限萧朝。如果您的應用在其清單中列出了正常權(quán)限,系統(tǒng)將自動授予該權(quán)限夏哭。如果您列出了危險權(quán)限检柬,則用戶必須明確批準您的應用使用這些權(quán)限。
Dangerous Permission竖配,是按照權(quán)限組分配使用的何址。如果app運行在Android 6.x的機器上里逆,對于授權(quán)機制是這樣的。如果你申請某個危險的權(quán)限用爪,假設(shè)你的app早已被用戶授權(quán)了同一組的某個危險權(quán)限原押,那么系統(tǒng)會立即授權(quán),而不需要用戶去點擊授權(quán)偎血。比如你的app對READ_CONTACTS已經(jīng)授權(quán)了班眯,當你的app申請WRITE_CONTACTS時,系統(tǒng)會直接授權(quán)通過烁巫。此外署隘,對于申請時彈出的dialog上面的文本說明也是對整個權(quán)限組的說明,而不是單個權(quán)限(ps:這個dialog是不能進行定制的)亚隙。
任何權(quán)限都可屬于一個權(quán)限組磁餐,包括正常權(quán)限和應用定義的權(quán)限。但權(quán)限組僅當權(quán)限危險時才影響用戶體驗阿弃≌锱可以忽略正常權(quán)限的權(quán)限組。
根據(jù)上面的介紹渣淳,我們又兩種解決方式
- 聲明權(quán)限為Normal Permissions脾还,也就是在(APP2中的
AndroidManifest.xml
)聲明權(quán)限的時候
<!-- 權(quán)限聲明 最后一行-->
<permission
android:name="me.febsky.PPPP"
android:label="@string/app_name"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="normal"/>
- 在運行時檢查是否獲得了這個自定義的dangerous權(quán)限,如果沒有那么動態(tài)申請一個入愧。如何動態(tài)申請權(quán)限
這時候要改造下發(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, "未授權(quán)!", 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上聲明的自定義權(quán)限的level是dangerous的棺蛛,那么在使用這個自定義的權(quán)限的app中要動態(tài)的申請這個權(quán)限怔蚌。(也就是要彈出一個請求授權(quán)的Dialog,讓用戶來授權(quán))