工作之余,想搞些感兴趣的东西,过程中涉及到隐藏原有APP的桌面图标并用另一个APP拉起隐藏图标的APP,于是我就想从头完整摸索一下,尽量把所有情况都测试一遍。
声明,以下测试均是针对需要拉起的APP的入口Activity进行的测试,如果想要被拉起的不是入口Activity,请另行测试
下面就开始吧!!(ps.测试过程中被拉起的APP取名为“PulledApp”,包名为“com.peng.administrator.pulledapp”,主动拉起PulledApp的项目取名为“PullApps”)
对于被拉起的APP。一般设置隐藏图标网上有很多说法,我们都尝试一下。
1. 修改Launcher Activity的intent-filter标签,把<category android:name="android.intent.category.LAUNCHER"/>
修改为<category android:name="android.intent.category.DEFAULT"/>
。
<!-- PulledApp -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
1.1(错误方式)在PullApps中,首先测试通过packageManager拉起APP
val intent = packageManager.getLaunchIntentForPackage("com.peng.administrator.pulledapp")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
经过测试,应用直接崩溃java.lang.IllegalStateException: intent must not be null
,因为intent为null,原因是我们在PulledApp的配置文件中找不到category为LAUNCHER的组件,因此无法获取到LaunchIntent。
1.2 (正确方式)其次测试设置Action和包名启动APP
val intent = Intent()
intent.action = Intent.ACTION_MAIN
intent.setPackage("com.peng.administrator.pulledapp")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
经过测试,该方式可以顺利拉起PulledApp。代码中为intent设置了包名,目的是让程序准确找到我们想要的应用,如果不设置包名,程序会弹出一个应用选择列表,其中包含了所有声明action为android.intent.action.MAIN的应用,在列表中我们可以选择PulledApp启动它。
1.3 (正确方式)使用显式intent启动,设置component
val intent = Intent()
val componentName = ComponentName("com.peng.administrator.pulledapp","com.peng.administrator.pulledapp.MainActivity")
intent.component = componentName
startActivity(intent)
经过测试,该方式可以顺利拉起PulledApp。
2. 修改Launcher Activity的intent-filter标签,删除<category android:name="android.intent.category.LAUNCHER"/>
。
<!-- PulledApp -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity>
2.1(错误方式)在PullApps中,首先测试通过packageManager拉起APP
代码同1.1, 经测试,该情况与1.1相同,均是java.lang.IllegalStateException: intent must not be null
2.2 (错误方式)其次测试设置Action和包名启动APP
代码同1.3
经过测试,设置action、category、package三者的任意组合都不能拉起app。android.content.ActivityNotFoundException: No Activity found to handle Intent
2.3 (正确方式)使用显式intent启动,设置component
val intent = Intent()
val componentName = ComponentName("com.peng.administrator.pulledapp","com.peng.administrator.pulledapp.MainActivity")
intent.component = componentName
startActivity(intent)
经过测试,该方式可以顺利拉起PulledApp。
3. 修改Launcher Activity的intent-filter标签,添加data声明。
<!-- PulledApp -->
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<data android:scheme="pulled_app"/>
<data android:scheme="pulled_app1" android:host="com.peng.administrator.pulledapp.mainactivity"/>
<data android:scheme="pulled_app2" android:host="com.peng.administrator.pulledapp.mainactivity"
android:path="/path"/>
</intent-filter>
</activity>
3.1(错误方式)使用packageManager启动APP或者为intent设置data启动APP
经过测试,当Activity的category仍然声明为LAUNCHER时,无法通过pachageManager启动APP,并且不管data怎么写,都无法拉起PulledApp(android.content.ActivityNotFoundException: No Activity found to handle Intent
)
3.2 (正确方式)使用显式intent启动,设置component
代码同1.3
经过测试,该方式可以启动APP。
4. 修改Launcher Activity的intent-filter标签,把<category android:name="android.intent.category.LAUNCHER"/>
修改为<category android:name="android.intent.category.DEFAULT"/>
添加data声明。
<!-- PulledApp -->
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="pulled_app"/>
<data android:scheme="pulled_app1" android:host="com.peng.administrator.pulledapp.mainactivity"/>
<data android:scheme="pulled_app2" android:host="com.peng.administrator.pulledapp.mainactivity"
android:path="/path"/>
</intent-filter>
</activity>
4.1 使用隐式Intent启动APP
测试结果请看注释
//val uri = Uri.parse("pulled_app:") //不行
//val uri = Uri.parse("pulled_app://") //不行
//val uri = Uri.parse("pulled_app://com.peng.administrator.pulledapp.mainactivity") //不行
//val uri = Uri.parse("pulled_app://com.peng.administrator.pulledapp.mainactivity/path") //行
//val uri = Uri.parse("pulled_app1:") //不行
//val uri = Uri.parse("pulled_app1://") //不行
//val uri = Uri.parse("pulled_app1://com.peng.administrator.pulledapp.mainactivity") //不行
//val uri = Uri.parse("pulled_app1://com.peng.administrator.pulledapp.mainactivity/path") //行
//val uri = Uri.parse("pulled_app2:") //不行
//val uri = Uri.parse("pulled_app2://") //不行
//val uri = Uri.parse("pulled_app2://com.peng.administrator.pulledapp.mainactivity") //不行
//val uri = Uri.parse("pulled_app2://com.peng.administrator.pulledapp.mainactivity/path") //行
val uri = Uri.parse("pulled_app2://com.peng.administrator.pulledapp.mainactivity:200/path") //行
val intent = Intent()
intent.action = Intent.ACTION_MAIN
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.setPackage("com.peng.administrator.pulledapp") //可以设置也可以不设置
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
所有测试不行的原因都是android.content.ActivityNotFoundException: No Activity found to handle Intent
。
可以看到只有scheme、host、path三者都参与uri的构建时才能成功调起app,由于PulledApp里面没有设定port,所以任意给一个port也可以。
注意:测试中在同一个intent-filter标签下定义了三个data,且有的之定义了scheme,有的定义了scheme、host,还有的定义了scheme、host、path。这种情况下的匹配规则是:(1) 在隐式intent定义时,必须将所有定义的字段都进行匹配,即在创建uri时需要填写的字段应与data定义最多的保持一致。例如测试中PulledApp同一个intent-filter中的三个data标签,第三个定义了三个字段,则在PullApps创建隐式intent时需要填写scheme、host、path的值,缺一不可。(2)在填写字段的值时,只要data中定义过的都可以使用,不一定非得根据某条data填写,例如scheme的值我们可以使用pulled_app、pulled_app1、pulled_app2,host的值我们可以使用com.peng.administrator.pulledapp.mainactivity,path的值我们可以使用/path。任何一个字段的值只要是在intent-filter中定义了就可以使用。
特别声明:
经过测试,如果PulledApp的intent-filter只有一个data,即如下代码时:
<!-- PulledApp -->
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="pulled_app"/>
</intent-filter>
</activity>
我们可以使用Uri.parse("pulled_app:")或Uri.parse("pulled_app://")来创建隐式intent。
4.2 使用显式Intent启动APP
代码同1.3
测试通过
结束语:
测试过程不全,望补充!!