下文皆使用 Client 表示操作的 App,Server 表示需要被唤起的远端 App,Server 的包名为 "com.jxx.server"
1. ComponentName
使用 ComponentName 唤起 Server 步骤很简单, 需要注意的是 Server 的 Activity 需要在 manifest 配置种设置 exported 为 true
Server 的配置如下:
- <activity Android:name="com.jxx.server.ServerActivity"
- Android:exported="true"/>
Client 调用如下:
- Intent intent1 = new Intent();
- ComponentName componentName = new ComponentName("com.jxx.server", "com.jxx.server.ServerActivity");
- intent1.setComponent(componentName);
- intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent1);
Intent 中添加 ComponentName 还有另外一种写法
- Intent intent2 = new Intent();
- intent2.setClassName("jxx.com.server", "jxx.com.server.MainActivity");
- intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent1);
只不过 setClassName 内部帮我们 new ComponentName 的实例
- public @NonNull Intent setClassName(@NonNull String packageName, @NonNull String className) {
- mComponent = new ComponentName(packageName, className);
- return this;
- }
既然是用 Intent 来唤起 Activity, 那就能使用 Intent 的特性, 例如使用 Bundle 传递数据
- Intent intent1 = new Intent();
- ComponentName componentName = new ComponentName("com.jxx.server", "com.jxx.server.ServerActivity");
- intent1.setComponent(componentName);
- Bundle bundle1 = new Bundle();
- bundle1.putString("remote_invoke", "from_client");
- intent1.putExtras(bundle1);
- intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent1);
在 Server 端提取数据也很简单
Bundle bundle = getIntent().getExtras();
2. 隐式跳转, Uri
Android 中唤起拨号页面是这样的
- Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + phoneNumber));
- startActivity(intent);
其实就是用 Uri 的形式唤起 Server, 并传递数据, 我们来自己实现一下. 这种方式下, Server 端的配置如下, 必须添加要有 action,data 以及 category:
- <activity Android:name=".SecondActivity">
- <intent-filter>
- <action Android:name="com.jxx.server.ServerActivity" />
- <data
- Android:host="com.jxx.server"
- Android:scheme="ServerActivity" />
- <category Android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
Client 调用:
- Intent intent2 = new Intent("com.jxx.server.ServerActivity");
- Uri uri = Uri.parse("ServerActivity://com.jxx.server?remote_invoke=from_client");
- intent2.setData(uri);
- startActivity(intent2);
我们看到 uri 中? 后面还加了 "remote_invoke=from_client", 这其实是用来给 Server 传递数据用的, 我们可以在 Server 中解析出来
- Uri uri = getIntent().getData();
- String from = uri.getQueryParameter("remote_invoke");
- //from = "from_client"
这里还有一个需要注意的点是, 如果 Client 在调用时没有指定 Action, 同时 Server 中又有多个 Activity 注册了相同的 scheme 和 host, 那么在页面跳转时, 系统会弹框让我们选择跳转到哪个页面, 如下图所示:
3. 通过 PackageManager 唤起
只需要知道 Server 的包名即可
- PackageManager packageManager = getPackageManager();
- Intent intent3 = packageManager.getLaunchIntentForPackage("com.jxx.server");
- if (intent3 != null) {
- startActivity(intent3);
- }
4. 静态广播接收者
只需要 Server 端注册一个静态广播接收者, 在广播接收者中跳转 Activity 即可, 客户端只需要发送一个广播.
Server 定义广播接收者:
- public class ServerBroadCastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Intent intent1 = new Intent(context, MainActivity.class);
- // 注意, 这里必须要添加这个 flag,
- // 原因在于这里的 context 并不是一个 Activity 类型的 context, 无法直接开启 activity
- intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent1);
- }
- }
并在 manifest 中注册为静态广播接收者, 并定义 action
- <receiver
- Android:name=".ServerBroadCastReceiver"
- Android:enabled="true"
- Android:exported="true">
- <intent-filter>
- <action Android:name="server.ServerBroadCastReceiver" />
- </intent-filter>
- </receiver>
Client 中发送广播即可
- Intent intent4 = new Intent("server.ServerBroadCastReceiver");
- // 这里加上 componentName 用于解决 8.0 以上不能唤起的问题
- ComponentName componentName = new ComponentName("com.jxx.server", "com.jxx.server.ServerBroadCastReceiver");
- intent4.setComponent(componentName);
- sendBroadcast(intent4);
5. Service
在 Android Service 详解 (二) 中我们介绍了如何通过 Service 实现 IPC 通信, 这当然也能用来唤起 App, 这里就不再过多介绍了, 有兴趣的同学可以点击查看.
来源: https://juejin.im/post/5c91fde2f265da60ea145b80