<activity
android:exported="true"
android:name=".other.ComponentActivity">
</activity>
或者:
<activity
android:name=".other.ComponentActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
</intent-filter>
</activity>
上面两种方式都是Activity组件导出的方式,主要是exported的值",为true时表示导出,Activity中exported的默认值:
<!-- 微信分享 -->
<activity
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
这样就会被安全机构检测出来的,如果不设置WXEntryActivity为组件导出,微信分享等功能根本就调不起来,这是官方的写法,我们认为这是必须要设置为组件导出,除非你把微信分享需求干掉,那业务不把你骂死;又或者是监听网络变化的广播接收器(7.0版本以上只能代码中动态注册才能接收该广播)、推送功能,集成过一些推送SDK都有印象,一些Service也会声明android:exported="true"等等。
<activity android:name="com.littlejerk.sample.other.WebActivity"/>
Activity的启动通常有两种方法
Intent intent = new Intent(getContext(),WebActivity.class);
intent.putExtra("URL","https://blog.csdn.net");
startActivity(intent);
<!-- 通过隐式启动的方式需要在AndroidManifest.xml文件声明-->
<activity android:name=".other.WebActivity">
<intent-filter>
<action android:name="com.littlejerk.sample.action.VIEW_URL" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
//调用方式启动WebActivity
Intent intent = new Intent();
intent.setAction("com.littlejerk.sample.action.VIEW_URL");
intent.putExtra("URL","https://blog.csdn.net");
startActivity(intent);
使用Action跳转,如果有一个程序的AndroidManifest.xml中的某一个 Activity的IntentFilter段中 定义了包含了相同的Action,那么这个Intent就与这个目标Action匹配。如果这个IntentFilter段中没有定义 Type、Category,那么这个 Activity就匹配了。但是如果手机中有两个以上的程序匹配,那么就会弹出一个对话框来提示说明。
Intent intent = getIntent();
String url = intent.getStringExtra("URL");
UILog.e(TAG, url.charAt(0));
mTvContent.setText(url);
我们注意到WebActivity只是接收一个URL并且显示出来(没有加载这个URL),从这里我们可以看出URL并没有做参数检验,应用可能会崩溃;因为该页面又是可被三方应用调用的,这时候如果别人恶意传递一些不良的网页信息,那你这个应用不拦截就直接加载了,则这个应用有可能就要下架了。
<permission
android:label="允许打开WebActivity页面权限"
android:name="com.littlejerk.sample.permission.WEB"
android:protectionLevel="signature" />
<!-- 通过隐式启动的方式需要在AndroidManifest.xml文件声明-->
<activity
android:permission="com.littlejerk.sample.permission.WEB"
android:name=".other.WebActivity">
<intent-filter>
<action android:name="com.littlejerk.sample.action.VIEW_URL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
在activity声明时,activity标签下有一个permission,通过permission就能指定保护该activity的权限名称了,这样,只有具有了该权限的activity才能启动它(注意在定义方和使用方都要在清单文件中定义和声明自定义的权限),在调用方的清单文件中声明和使用该权限:
<!--调用方可不用声明-->
<permission
android:label="允许打开WebActivity页面权限"
android:name="com.littlejerk.sample.permission.WEB"
android:protectionLevel="signature" />
<!--调用方必须申请此权限-->
<uses-permission android:name="com.littlejerk.sample.permission.WEB"/>
有了权限的控制,activity组件导出的范围就可控了,当我们公司应用间存在相互的组件调用时,就可以使用同签名的权限来做限制,至于其它应用因为不是相同的签名,所以它们无法调用我们暴露出去的组件,这很有效地规避了风险。 广播发送方
发送方需要在清单文件AndroidManifest.xml中声明权限:
<permission
android:label="声明发送方权限"
android:name="com.littlejerk.sample.permission.BROADCAST_SEND"
android:protectionLevel="signature" />
然后使用sendBroadcast(Intent intent, String receiverPermission)方法发送广播:
//发送广播
Intent intent = new Intent();
intent.setAction("com.littlejerk.sample.broadcast.action.TEST");
sendBroadcast(intent, "com.littlejerk.sample.permission.BROADCAST_SEND");
从receiverPermission字面意思就知道,接收广播方必须要申请com.littlejerk.sample.permission.BROADCAST_SEND这个自定义权限,不然,无法接收到action通知,如接收方的清单文件AndroidManifest.xml:
<!-- 接收方需申请发送方权限-->
<uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_SEND"/>
如果接收方的广播接收器不控制自己的权限,则同开发者应用只监听com.littlejerk.sample.broadcast.action.TEST这个action就行了,但是为了双重检验,我们也需要给接收方声明自己的权限。
广播接收方
我们定义一个广播接收器TestReceiver:
public class TestReceiver extends BroadcastReceiver {
private static final String TAG = "TestReceiver";
//接收到广播信息的回调
@Override
public void onReceive(Context context, Intent intent) {
//对外来的参数应该做些合法的检查
String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
return;
}
UILog.e(TAG, "action:" + action);
}
}
接着在清单文件AndroidManifest.xml中声明控制权限:
<permission
android:label="声明接收方权限"
android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"
android:protectionLevel="signature" />
然后把这个控制权限给广播接收器,接收器有两种注册方式
<receiver
android:name=".widget.receiver.TestReceiver"
android:permission="com.littlejerk.sample.permission.BROADCAST_RECEIVER">
<intent-filter>
<action android:name="com.littlejerk.sample.broadcast.action.TEST"/>
</intent-filter>
</receiver>
然后是动态注册方式,在你需要注册的地方声明:
Receiver receiver = new Receiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.littlejerk.sample.broadcast.action.TEST");
registerReceiver(receiver, intentFilter, "com.littlejerk.sample.permission.BROADCAST_RECEIVER", null);
这两种注册方式都可以,但是推荐使用动态注册广播的方式,因为Android O上为了App性能和功耗的考虑,对静态注册的广播做了很大的限制,至于是什么限制,这里就不说了。
<!-- 发送方需申请接收方权限-->
<uses-permission android:name="com.littlejerk.sample.permission.BROADCAST_RECEIVER"/>
至此,广播的双向检验就完成了,以上所有代码都测试过了,没有任何问题,很好地过滤了无关广播,保护了组件的安全。