前言: 唉唉,又是一个剁手的日子啊,当大家还沉浸在双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