目录
一、背景
近日,微博官方发布了一项新功能,即可以在App设置中动态更换微博的显示图标样式。根据微博官方的说法,除了最原始的图标外,微博还推出了另外10种不同的样式,既有3D微博、炫彩微博等保留了眼睛造型的新样式,也有奶酪甜馨、巧克力等以食物命名的“新口味”,还有梦幻紫、幻想星空等抽象派新造型,给了微博用户多种选择的自由。
不过需要注意的是,这一功能并不是面对所有人开放的,只有微博年费会员才能享受。此外,iOS 10.3及以上和Android 10及以上系统版本支持该功能,但是iPad与一加8Pro手机无法使用该功能。因部分手机存在系统差异,会导致该功能不可用,微博方面后续还会对该功能进行进一步优化。
二、技术实现
其实,说到底,上述功能用到的是动态更换桌面图标的技术。如果说多年以前,实现图标的切换还是一种时髦的技术,那么,我们可以直接使用PackageManager就可以实现动态更换桌面图标。
实现的细节是,在Manifest文件中使用标签准备多个Activity入口,没个activity都指向入口Activity,并且为每个拥有标签的activity设置单独的icon和应用名,最后调用SystemService 服务kill掉launcher,并执行launcher的重启操作。
首先,我们在AndroidManifest.xml文件中添加如下代码:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.xzh.demo"> <!-- 权限--> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> <application android:allowBackup="true" android:icon="@mipmap/wb_default_logo" android:label="@string/app_name" android:roundIcon="@mipmap/wb_default_logo" android:supportsRtl="true" android:theme="@style/Theme.AndroidDemo"> ...//省略其他代码 <!-- 默认微博--> <activity-alias android:name="com.xzh.demo.default" android:targetActivity=".MainActivity" android:label="@string/app_name" android:enabled="false" android:icon="@mipmap/wb_default_logo" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity-alias> <!-- 3D微博--> <activity-alias android:name=".threedweibo" android:targetActivity=".MainActivity" android:label="@string/wb_3d" android:enabled="false" android:icon="@mipmap/wb_3dweibo" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity-alias> ... //省略其他 </application> </manifest>
上面配置中涉及到的属性如下:
- android:name:注册的组件名字,启动组件的名称。
- android:enabled:是否启用这个组件,也就是是否显示这个入口。
- android:icon:图标
- android:label:名称
- android:targetActivity:默认的activity没有这个属性,指定目标activity,与默认的activity中的name属性是一样的,需要有相应的java类文件。
接着,我们在MainActivity触发Logo图标更换逻辑,代码如下:
class MainActivity : AppCompatActivity() { var list: List<LogoBean> = ArrayList() var recyclerView: RecyclerView? = null var adapter: LogoAdapter? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initView() initData() initRecycle() } private fun initView() { recyclerView = findViewById(R.id.recycle_view) } private fun initData() { list = Arrays.asList( LogoBean(R.mipmap.wb_default_logo, "默认图标", true), LogoBean(R.mipmap.wb_3dweibo, "3D微博", false), LogoBean(R.mipmap.wb_cheese_sweetheart, "奶酪甜心", false), LogoBean(R.mipmap.wb_chocolate_sweetheart, "巧克力", false), LogoBean(R.mipmap.wb_clear_colorful, "清透七彩", false), LogoBean(R.mipmap.wb_colorful_sunset, "多彩日落", false), LogoBean(R.mipmap.wb_colorful_weibo, "炫彩微博", false), LogoBean(R.mipmap.wb_cool_pool, "清凉泳池", false), LogoBean(R.mipmap.wb_fantasy_purple, "梦幻紫", false), LogoBean(R.mipmap.wb_fantasy_starry_sky, "幻想星空", false), LogoBean(R.mipmap.wb_hot_weibo, "热感微博", false), ) } private fun initRecycle() { adapter =LogoAdapter(this,list); val layoutManager = GridLayoutManager(this, 3) recyclerView?.layoutManager = layoutManager recyclerView?.adapter = adapter adapter?.setOnItemClickListener(object : OnItemClickListener { override fun onItemClick(view: View?, position: Int) { if(position==1){ changeLogo("com.xzh.demo.threedweibo") }else if (position==2){ changeLogo("com.xzh.demo.cheese") }else if (position==3){ changeLogo("com.xzh.demo.chocolate") }else { changeLogo("com.xzh.demo.default") } } }) } fun changeLogo(name: String) { val pm = packageManager pm.setComponentEnabledSetting( componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP ) pm.setComponentEnabledSetting( ComponentName(this, name), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) reStartApp(pm) } fun reStartApp(pm: PackageManager) { val am = getSystemService(ACTIVITY_SERVICE) as ActivityManager val intent = Intent(Intent.ACTION_MAIN) intent.addCategory(Intent.CATEGORY_HOME) intent.addCategory(Intent.CATEGORY_DEFAULT) val resolveInfos = pm.queryIntentActivities(intent, 0) for (resolveInfo in resolveInfos) { if (resolveInfo.activityInfo != null) { am.killBackgroundProcesses(resolveInfo.activityInfo.packageName) } } } }
注意上面的changeLogo()方法中的字符串需要和AndroidManifest.xml文件中的<activity-alias>
的name相对应。运行上面的代码,然后点击应用中的某个图标,就可以更换应用的桌面图标,
如下图所示:
不过,测试的时候也遇到
一些适配问题:
- 小米9:版本升级时,新版本在AndroidManifest中删除A3,老版本切换图标到A3,为卸载直接覆盖安装新版本,手机桌面图标消失。
- magic 4:版本升级时,新版本在AndroidManifest中删除A3,老版本切换图标到A3,为卸载直接覆盖安装新版本,手机桌面图标切换到默认图标,但点击之后未能打开APP。