Android实现更新应用启动图标和名称

对于动态更新应用图标和名称这个小功能还是有一定使用场景的。比如节假日或者特惠活动时候我们需要展示一些特殊的图标。要是重新打包发布那岂不是很麻烦。

我最近使用迅雷APP,就发现了有这个功能,会员还可以享受会员专享图标,展示你的与众不同。

Android实现更新应用启动图标和名称

那怎么实现这个功能,下面就来详细介绍下,要实现这个功能主要涉及两个知识点:activity-aliassetComponentEnabledSetting

activity-alias

这是在清单文件里面配置的属性,字面意思就是活动的别名。

<activity-alias
    android:name="launcherB"
    android:enabled="true"
    android:exported="true"
    android:icon="@mipmap/ic_launcher_b"
    android:label="B图标应用"
    android:roundIcon="@mipmap/ic_launcher_b_round"
    android:targetActivity=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity-alias>

属性基本和<activity>一样,唯一区别android:targetActivity指定该活动别名跳转的页面。当我们在清单文件配置上述的内容后,就会在桌面多出来一个启动应用的图标,当你点击该图标时候就会跳转到MainActivity

Android实现更新应用启动图标和名称

setComponentEnabledSetting

setComponentEnabledSetting(@NonNull ComponentName componentName,
            @EnabledState int newState, @EnabledFlags int flags);

该方法是包管理器PackageManger中的方法,可以配置清单文件中组件是否可用。而第二个参数其实就是android:enabled="true"该属性的配置。
正如上面我们配置了enable=true所以桌面会显示B图标,当配置为enable=false,那么B图标就不会显示。setComponentEnabledSetting就是起到这样一个效果。

============================================
有了上面两个知识点我们就可以实现切换图标和名称。

1. 首先我们在清单文件中配置好启动页面和活动别名

...
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity-alias
            android:name="launcherA"
            android:enabled="false"
            android:exported="true"
            android:icon="@mipmap/ic_launcher_a"
            android:label="A图标应用"
            android:roundIcon="@mipmap/ic_launcher_a_round"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias
            android:name="launcherB"
            android:enabled="false"
            android:exported="true"
            android:icon="@mipmap/ic_launcher_b"
            android:label="B图标应用"
            android:roundIcon="@mipmap/ic_launcher_b_round"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>

这里需要注意,launcherA和launcherB的android:enable属性要配置为false,要不然你应用安装界面就会有三个图标了,岂不是很尴尬。

2. 我们在MainActivity中实现切换图标

MainActivity.kt

class MainActivity : AppCompatActivity() {

    private var app: String = LauncherSwitch.APP

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.show_switch_launcher)
        findViewById<RadioGroup>(R.id.rg_app).setOnCheckedChangeListener { _, checkedId ->
            app = when (checkedId) {
                R.id.rb_app_a -> LauncherSwitch.APP_A
                R.id.rb_app_b -> LauncherSwitch.APP_B
                else -> LauncherSwitch.APP
            }
        }
        findViewById<Button>(R.id.btn_switch_launcher).setOnClickListener {
            LauncherSwitch.enableLauncher(this, app)
        }
    }

}

show_switch_launcher.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RadioGroup
        android:id="@+id/rg_app"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:checkedButton="@id/rb_app_origin"
        android:gravity="center"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <RadioButton
            android:id="@+id/rb_app_origin"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableStart="@mipmap/ic_launcher"
            android:text="原应用" />

        <RadioButton
            android:id="@+id/rb_app_a"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableStart="@mipmap/ic_launcher_a"
            android:text="A应用" />

        <RadioButton
            android:id="@+id/rb_app_b"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableStart="@mipmap/ic_launcher_b"
            android:text="B应用" />
    </RadioGroup>

    <Button
        android:id="@+id/btn_switch_launcher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="切换图标和应用"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

LauncherSwitch.kt

/**
 * 应用图标和名称更新工具类
 */
object LauncherSwitch {

    const val APP = "com.sample.MainActivity"
    const val APP_A = "com.sample.launcherA"
    const val APP_B = "com.sample.launcherB"

    @StringDef(
        value = [APP, APP_A, APP_B]
    )
    @kotlin.annotation.Retention(AnnotationRetention.SOURCE)
    annotation class AppLauncher

    fun enableLauncher(context: Context, @AppLauncher name: String) {
        context.packageManager.run {
            setComponentEnabledSetting(
                ComponentName(context, APP),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP
            )
            setComponentEnabledSetting(
                ComponentName(context, APP_A),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP
            )
            setComponentEnabledSetting(
                ComponentName(context, APP_B),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP
            )
            setComponentEnabledSetting(
                ComponentName(context, name),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP
            )
        }
    }
}

这样我们就可以实现动态切换图标和名称,

其实我们看看迅雷的清单文件也是通过配置多个活动别名来实现切换启动图标和名称
Android实现更新应用启动图标和名称

上一篇:Android8.0后获取Apk的icon区别


下一篇:Android中禁用组件(如Receiver或Activity等)