App 共享组件

如果想要在不同的 App 之间共享 Activity、Service 或广播等,通常有如下三种方法:

  1. 完全暴露:使用 android:exported="true" 来将组件设置为其他 App 都可调用。一般来说还需要指定 里面的 参数
  2. 权限暴露:在 App A 中使用 定义权限,然后在 App B 中使用 申请权限调用 App A 中的组件。
  3. 私有暴露:如果一个公司有两个 App,只想在这两个 App 中相互调用,那么就必须设置 sharedUserId,将两个 App 的 UID 设置为一样的。

下面针对这三种方案进行详细说明。

完全暴露

如果 Client App 的一个 Activity 想要启动 Server App 的 ServerActivity ,那么就需要把 ServerActivity 暴露出去,一般通过添加 来实现。

1
2
3
4
5
6
7
<activity
android:name=".ServerActivity">
<intent-filter>
<action android:name="eateeer.me" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

当为一个组件添加 时,那么该组件的 exported 属性默认为 true。

这时,Client App 就可以像下面这样来启动 SeverActivity:

1
2
3
intent.setAction("eateeer.me");
intent.addCategory("android.intent.category.DEFAULT");
startActivity(intent);

但是使用这种方式,出了 Client App 可以启动 ServerActivity 以外,其他 App 都能通过上面的代码启动 ServerActivity。

权限暴露

如果我们不想其他的 App 肆无忌惮的调用我们的组件,那么你可以增加一些限制,比如要求对方声明相应的权限才能使用。这样我们就需要自定义权限。

自定义 Activity 和 Service 权限

如果我们想给 Activity 或 Service 设置权限,那么可以在 AndroidManifest.xml 文件中使用 声明新的权限内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eateeer.me"
android:sharedUserId="eateeer.me">

<permission
android:name="eateeer.me.permission.ServerActivity"
android:label="@string/server_permission_label"
android:description="@string/server_permission_description"
android:protectionLevel="normal" />
...
...
<activity
android:name=".ServerActivity"
android:permission="eateeer.me.permission.ServerActivity">
<intent-filter>
<action android:name="eateeer.me" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</manifest>

标签下有四个属性:

  • name:权限名,这个字符串对应于 Client App 的 中的 name。
  • label:标签
  • description:描述该权限的内容
  • protectionLevel:保护级别。常用的有四种:
    • normal:默认的保护级别。表示使用该权限不会有什么风险,安装的时候会自动授予该权限,无需用户确认。
    • dangerous:危险权限。表示该权限可以访问到用户的数据或者在某种形式上控制设备。这种权限需要用户确认后才能授予。
    • signature:签名权限。表示只有拥有相同证书的应用程序才能使用该权限,这种权限级别已经非常高了。
    • signatureOrSystem:这个保护级别表示系统镜像中的应用和具有相同签名的应用都可以使用该权限。

举个例子,比如百度地图 apk 的 AndroidManifest.xml 里面定义了一个权限,

  • 如果权限的保护级别为 normaldangerous,表示其他 app 都可以使用该权限。
  • 如果权限的保护级别为 signature,那么只有使用同样私钥签名的 apk 才能使用该权限,比如百度网盘。
  • 如果权限的保护级别为 signatureOrSystem,那么除了拥有同样私钥签名的 apk,比如百度网盘,可以使用该权限外,在 /system/app/ 下的应用也可以使用该权限。

也就是说,通过 protectionLevel 属性的值,我们可以限制该权限是否可以给 “外人” 使用。如果我们希望该权限只有公司的产品才能用的话,那么可以设置为 signature

Server App 里面定义了权限,如果要使用的话,在 Client App 的 AndroidManifest.xml 文件中申明即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eateeer.me.client">

<uses-permission android:name="eateeer.me.permission.ServerActivity"/>

<application
android:icon="@mipmap/ic_launcher">
<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>

私有暴露

在 Android 里面,每个 App 都有一个唯一的 linux user ID,即该应用程序的文件只有该 linux user 可以访问。如果我们想要让其他的程序也能访问到我们 App 里面的数据,就需要使用 ShareUserId,也就是让两个 apk 使用相同的 userID。

即在 Server App 和 Client App 的 AndroidManifest.xml 都增加相同的 sharedUserId 字符串。

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eateeer.me"
android:sharedUserId="eateeer.me">
......
</manifest>

注意,sharedUserId 字符串中要包含至少一个 . 分隔符

如果觉得文章对你有帮助,请我喝杯可乐吧