冷知识 —— 如何实现 LeakCanary 桌面多出一个“新应用”的效果

3,228 阅读3分钟

很多人都有用过开源的内存检测工具 LeakCanary,在 demo 应用中接入该库后,安装到手机里,发现手机桌面除了自己的项目外,会神奇地多出一个名叫 Leaks 的“应用”(如下图)。原来,在自有应用中发生如 Acitivty 泄漏时,LeakCanary 会及时生成并分析其泄漏路径保存起来。这个“新应用”相当于一个快捷入口,打开后便会有 demo 应用的历史内存泄漏信息,非常方便。

这种特殊的设计看起来好像是同时安装了两个不同的 app 在手机当中,但我们都知道,这是不可能的。仔细查看新的 Leaks “应用”的信息,发现它其实就是 demo 应用,只是 demo 应用在桌面同时拥有了两个图标,Leaks 点击后会打开一个新的 Activity,专门用于展示内存泄漏的信息,只是体验起来像是多安装了一个应用而已。这种有趣的交互实现起来其实非常简单,只需要使用 <activity-alias> 标签即可。

<activity-alias>

<activity-alias>,顾名思义,Activity 的别名,是在应用清单文件 AndroidManifest.xml 中申明,在 <application> 标签之下。

语法大致如下:

<activity-alias android:enabled=["true" | "false"]
                android:exported=["true" | "false"]
                android:icon="drawable resource"
                android:label="string resource"
                android:name="string"
                android:permission="string"
                android:targetActivity="string" >
                . . .
</activity-alias>

<activity-alias> 会包含一个目标 Activity,具有自己的一组 Intent 过滤器,Intent 过滤器可以指定 android.intent.action.MAINandroid.intent.category.LAUNCHER 标志,这样就会以一个新的图标入口出现在手机的桌面启动器当中。

示例如下:

<application
    . . .>
    
    . . .
    
    <activity
        android:name=".SecondActivity"/>
    
    <activity-alias
        android:name="com.jason.demo.dynamicshortcut.ShortcutLauncherActivity"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher_alias"
        android:label="ActivityAlias"
        android:targetActivity=".SecondActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>
    
</application>

其中,android:targetActivity 指定所必须的打开的目标 Activity,对应着一个在 AndroidManifest.xml 中申明的 <activity>android:name 是别名的唯一名称,不引用实际类android:icon 以及 android:label 指定一个新的图标和标签给用户。

申明后,便会在手机内看到两个应用图标入口,示例如下:

但体验下来会发现,主图标打开 Main Activity 后,alias 图标点击还是打开 Main Activity,是因为此时 Main Activity 和 Second Activity 有着一样的相似性

taskAffinity

Activity 会继承为应用设置的相似性(taskAffinity 属性)。应用默认相似性的名称为 <manifest> 元素所设置的包名。具有同一相似性的 Activity 归属同一任务(从用户的角度来看,则是归属同一“应用”)。

因此,需要根据自身的需求,考虑对不同的 Activity 赋予不同的相似性。对于“新应用”的效果,则需要对 Second Activity 设置不同的相似性,示例如下:

<activity
    android:name=".SecondActivity"
    android:taskAffinity="com.jasonwu.${applicationId}" />

最终,“双应用”入口的效果就这样轻易实现啦:

本次的分享就到这啦,喜欢的话可以点个赞 👍 或关注呗。如有错误的地方欢迎大家在评论里指出。

另外,对于这些零碎的 Android 知识点,笔者从自身的经验出发,以文档的形式进行整理放在 Github 上,每周不定时更新,欢迎大家 star。