最新在给 V2er 添加Android 7.1开始支持的一个新特性shortcuts时遇到了一些坑。这里总结一下供大家参考。

坑1 - targetPackage不支持Variant字符串引用

是这样的,如果你的APP构建了两个变种比如(pay, free)而不同的变种对应的applicationId肯定是不同的,为了少定义一个 shortcuts.xml 文件,你可能会想通过在不同变种下分别定义一个 string 资源类型来达成差异构建,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_shortcuts_hot"
android:shortcutId="dailyHot"
android:shortcutShortLabel="@string/shortcuts_daily_hot">

<intent
android:action="shortcuts_daily_hot"
android:data="v2er://me.ghui.v2er/daily_hot"
android:targetClass="me.ghui.v2er.module.general.RouteActivity"
android:targetPackage="@string/pkg_name" />

</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/ic_shortcuts_new"
android:shortcutId="newPost"
android:shortcutShortLabel="@string/shortcuts_new_post">

<intent
android:action="shortcuts_create_topic"
android:data="v2er://me.ghui.v2er/create_topic"
android:targetClass="me.ghui.v2er.module.general.RouteActivity"
android:targetPackage="@string/pkg_name" />

</shortcut>
</shortcuts>

上面引用的 @string/pkg_name 在 free 与 pay 变种下各有一份。对应的名称分别是
me.ghui.v2er.freeme.ghui.v2er,看上去没什么问题,而且如果你在一些第三方Launcher比如Nova Launcher中去运行不管是 free变种还是pay变种都是没问题的。可如果你在一台Android 7.1及以后的原生Launcher上去运行就会报 App not install 错误。

解决方法:
其实在StackOverflow上也有人问类似的问题,这里是没有什么好方法的,我现在采用的方法就是在两种变种下分别写一份 shortcuts.xml 而这两份文件的区别就在 targetPackage处。(关于为什么在Nova上没问题这一点我没想通),总之,这里不能通过定义变种字符串资源来差异构建。

坑2 - 兼容7.1之前的系统

shortcuts虽然是android 7.1开始才有的特性,但也是可以兼容第三方Launcher的(比如Nova),当然需要这些Launcher支持才行。
在网上能看到的一些总结都说通过静态方式创建的shortcuts是可以自动兼容的,实际上还是要做一些工作的。比如像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_shortcuts_hot"
android:shortcutId="dailyHot"
android:shortcutShortLabel="@string/shortcuts_daily_hot">

<intent
android:action="shortcuts_daily_hot"
android:data="v2er://me.ghui.v2er/daily_hot"
android:targetClass="me.ghui.v2er.module.general.AActivity"
android:targetPackage="me.ghui.v2er" />

</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/ic_shortcuts_new"
android:shortcutId="newPost"
android:shortcutShortLabel="@string/shortcuts_new_post">

<intent
android:action="shortcuts_create_topic"
android:data="v2er://me.ghui.v2er/create_topic"
android:targetClass="me.ghui.v2er.module.general.BActivity"
android:targetPackage="me.ghui.v2er" />

</shortcut>
</shortcuts>

上面定义的两个Shortcuts对应的targetClass分别为 AActivity与BActivity,如果是在原生的系统的原生Launcher上这样写是没什么问题的,如果是Nova这样的第三方Launcher就会有问题。解决方法有两种,
解决方法1:
分别给这两个Activity在Manifest文件对应位置添加
<action android:name="android.intent.action.MAIN" />

解决方法2:
通过一个带有 <action android:name="android.intent.action.MAIN" /> 的Activity来转发,通常情况下就是App启动的第一个Activity,比如SplashActivity, 这样在 shortcuts文件中所有的targetClass都指定为这个Activity,然后在这个Activity启动时根据intent所包裹的 action或data等的不同来决定去具体启动哪个Activity。通过这种方式的好处就是不需要为每个通过shortcuts启动的activity添加 <action android:name="android.intent.action.MAIN" /> 的filter。

坑3 - shortcuts菜单不自动关闭

这个问题只在原生Launcher上存在。如果你用shortcuts方式启动的Activity设置了 <item name="android:windowIsTranslucent">true</item> 即window透明,点击shortcuts相应item启动Activity后,当你再次返回到桌面时,会发现之前的shortcuts菜单并没有消失,仍然是弹出状态。
如果你用了 Slidr 这种滑动返回库时会遇到这样的问题。

解决方法:
就是给这些需要通过shortcuts方式启动的Activity不设置window透明。但是如果你需要用到滑动返回的话又不能不设透明。我的解决方法就是给这些需要通过shortcuts方式启动的Activity分别派生一个子类,然后给这些子类在manifest文件中指定不带透明窗口的主题。然后在shortcuts.xml文件里targetClass指定为这些windown不透明的activity,在App内部其它部分还使用透明window的那些activity。通过这种方式的一个缺点就是需要多写几个activity(其实也还好,因为shortcuts最多只能指定4个)。


版权声明

文章版权归本人所有,如需转载需在明显位置处保留作者信息及原文链接 !