热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

动态切换App桌面icon跟text,让你的应用炫起来(Android)!!

前言:唉唉,又是一个剁手的日子啊,当大家还沉浸在双11买什么的时候,我在想:“手机上的天猫,淘宝,支付宝应用的icon都变成了双11了,不得不感叹这些公司的产品手段真的高!!这无形中打了多少广

前言: 唉唉,又是一个剁手的日子啊,当大家还沉浸在双11买什么的时候,我在想:“手机上的天猫,淘宝,支付宝应用的icon都变成了双11了,不得不感叹这些公司的产品手段真的高!!这无形中打了多少广告啊。”于是我就打算去研究一下,下面就把我研究的东西分享一下哦,没错,这就是程序猿所看到的“11.11”(^__^) 嘻嘻……

其实吧,实现原理还是相当简单的,主要是用到了Activity的activity-alias这个标签,在此之前了,我们还要去了解点其它东西:
我们都知道一个app的主入口是带有如下标记的Activity,如:

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

如果我们都不配置的话,会怎样呢?:

<activity  android:name=".MainActivity" >

        activity>

我们运行代码看看效果:
as直接报错,错误信息为”当启动app的时候,默认的Activity没有找到“

Could not identify launch activity: Default Activity not found
Error while Launching activity

我们改改代码,只保留一个:

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

再次运行代码:

Could not identify launch activity: Default Activity not found
Error while Launching activity

还是一样的错误!于是我们保留:

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

运行代码:

Could not identify launch activity: Default Activity not found
Error while Launching activity

还是一样的错误!~如果两个都写的话,那就说明此Activity为app的入口了,我就不测试了。

* 接下来我们配置多个引用的入口:*

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

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity android:name=".TestActivity" android:icon="@mipmap/aa" android:label="测试1" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

我们配置了一个TestActivity,然后加上了另外一个icon跟label,
我们再次运行代码:

在4.0以上的手机显示效果:
这里写图片描述

可以看到,显示了一个icon,但是在4.0以下的手机上显示了两个icon(抱歉啊!可以是机器太老了,所以用as截不屏幕…),我也不懂额。
可能原因1是:4.0以上默认检查过了如果有多个就默认显示第一个,4.0以下的是不会检查的,直接安装多个。
可能原因2是:不同的手机桌面应用会自动检查是否有多个,如果存在就安装第一个(因为我以前也做过一个桌面的应用,在拿比如相机应用的时候,会出现两个icon)。
当然!我也不太确定具体原因,如果有小伙伴知道的,记得在评论区告诉一下我哈~~

接下来进入我们研究的重点。
那什么activity-alias标签呢?
顾名思义,也就是activity的一个别名,android允许一个activity有多个别名。

activity-alias功能又是什么呢?

知道了activity-alias的概念,那么它的功能是什么呢?activity-alias作为一个已存在Activity的别名,则应该可以通过该别名标签声明快速打开目标Activity。因此activity-alias可用来设置某个Activity的快捷入口,可以放在桌面上或者通过该别名被其他组件快速调起。该标签元素支持一些属性及intent-filter、meta-data等配置,因此可以触发一些跟目标Activity不同的功能逻辑,虽然打开的是同一个Activity。举个简单的例子,如之前需要先打开主界面,然后才能点击进入某个Activity,如果使用activity-alias为该Activity配置一个快捷入口,甚至可以为其在桌面生成一个图标,然后点击桌面图标可直接进入该Activity,该功能可满足某些需要快速到达功能界面的需求。

activity-alias基本用法:

"true" | "false"]
                android:exported=["true" | "false"]
                android:icon="drawable resource"
                android:label="string resource"
                android:name="string"
                android:permission="string"
                android:targetActivity="string" >
    ...

一些属性的解释:

属性 含义
android:enabled 是否其作用,比如配置了多个activity-alias,如果想要有一个有效,就配置成 android:enabled=true
android:exported 该属性为true的话,则目标Activity可被其他应用调起,如为false则只能被应用自身调起。其默认值根据activity-alias是否包含intent-filter元素决定,如果有的话,则默认为true;没有的话则为false。其实也很好理解,如果有intent-filter,则目标Activity可以匹配隐式Intent,因此可被外部应用唤起;如果没有intent-filter,则目标Activity要被调起的话必须知道其精确类名,因为只有应用本身才知道精确类名,所以此时默认为false。
android:icon 该属性就比较好玩了,允许自定义icon,可以不同于应用本身在桌面的icon。如果需要在桌面上创建快捷入口,也许产品会要求换个不同的icon
android:label 该属性类似于android:icon,图标都换了,换个名称也合情合理吧,此属性就是为此而生的。
android:name 该activity-alias的名字
android:permission 该属性指明了通过别名声明调起目标Activity所必需的权限
android:targetActivity 该属性指定了目标Activity,即通过activity-alias调起的Activity是哪个,此属性其实类似于activity标签中的name属性,需要规范的Activity包名类名。

先看一下某猫的icon,
平时的时候我们手机桌面可能是这样的
这里写图片描述

然后快要到双11的时候,又变成了:
这里写图片描述

有童鞋可能会这么时候了,是不是升级版本了?是的!!有这种可能性,但是我想他们应该是不会这么做的,应该每次为了一个icon做一次升级,不划算哦!!做法大致是“在每一次升级版本的时候,把这些节日性的icon跟文字提前嵌入到app中,然后需要切换的时候,后台只需要推送一条信息,前端接收到消息后更换icon”。

下面,根据我们的思路来实现一下我们的功能:

我们改改manifest.xml代码

<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            intent-filter>
        activity>
        <activity-alias  android:name="com.yqy.mylauchdemo.ActivityAlias1" android:enabled="true" android:icon="@mipmap/ic_launcher" android:label="正常的icon" 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="com.yqy.mylauchdemo.ActivityAlias2" android:enabled="false" android:icon="@mipmap/festival" android:label="双11啦!" android:targetActivity=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity-alias>

添加了两个alias,一个是普通的icon,默认android:enabled=true,
比如有很多个,那么其它的alias设置成android:enabled=false,
我们运行代码:
这里写图片描述

可以看到,显示的是我们ActivityAlias1配置的效果。
接下来我们模拟一下后台推送消息过后替换成ActivityAlias2的效果(代码很简单,我就直接贴了):

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ///模拟网络推送消息的过程,其实这个应该放在一个service里面悄悄运行的,我就不演示了
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                setIcon(ACTIVITY_ALIAS_2);
            }
        },5000);
    }
    private void setIcon(String activity_alias) {
        Context ctx = getApplication();
        PackageManager pm = ctx.getPackageManager();
        // 使ACTIVITY_ALIAS_1失效
        pm.setComponentEnabledSetting(
                new ComponentName(ctx, ACTIVITY_ALIAS_1),
                ACTIVITY_ALIAS_1.equals(activity_alias) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
        // 使ACTIVITY_ALIAS_2生效
        pm.setComponentEnabledSetting(
                new ComponentName(ctx, ACTIVITY_ALIAS_2),
                ACTIVITY_ALIAS_2.equals(activity_alias) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
                Log.e("TAG", "setIcon----success!!");
      }

运行代码,当我们在log中看到“setIcon—-success!!”后,我们退出app看看桌面的icon替换了没:
这里写图片描述

可以看到,虽然效果是达到了,但是当系统的桌面app检测到我们的app的icon跟上一次不一样的时候,我们再次点击我们的app会报一个错误,这样肯定不行额,用户体验太差了。

* 我们应该在更改完icon后让桌面app重启一下,这样就不会出现这种情况了: *

  private void setIcon(String activity_alias) {
        Context ctx = getApplication();
        PackageManager pm = ctx.getPackageManager();
        // 使ACTIVITY_ALIAS_1失效
        pm.setComponentEnabledSetting(
                new ComponentName(ctx, ACTIVITY_ALIAS_1),
                ACTIVITY_ALIAS_1.equals(activity_alias) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
        // 使ACTIVITY_ALIAS_2生效
        pm.setComponentEnabledSetting(
                new ComponentName(ctx, ACTIVITY_ALIAS_2),
                ACTIVITY_ALIAS_2.equals(activity_alias) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

        Log.e("TAG", "setIcon----success!!");
        //干掉桌面app,让它自动重启。
        ActivityManager am = (ActivityManager) ctx.getSystemService(Activity.ACTIVITY_SERVICE);
        Intent i = new Intent(Intent.ACTION_MAIN);
        i.addCategory(Intent.CATEGORY_HOME);
        i.addCategory(Intent.CATEGORY_DEFAULT);
        List resolves = pm.queryIntentActivities(i, 0);
        for (ResolveInfo res : resolves) {
            if (res.activityInfo != null) {
                am.killBackgroundProcesses(res.activityInfo.packageName);
            }
        }
    }

小伙伴们记得加一下权限哦!!

 <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

再次运行我们的app,让看到log的时候,退出app看看是否改变:
这里写图片描述

当我们看到log的时候,我们返回,会发现桌面卡住了,卡了一会后桌面显示出了我们替换的icon了,看到这是不是有点明白了什么了呢?(^__^)!! 当我们用手机看其他app的时候,有的时候退出app会看到卡屏的现象,这个时候作程序员的你应该是明白了是怎么回事了哈!!!!!!!

好了,本文就介绍到这里了!
参考文章:
http://blog.csdn.net/ahence/article/details/51648768


推荐阅读
author-avatar
怎么又是你呀
你讲话咧,撸起袖子加油干!!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有