Android 适配多种ROM的快捷方式
快捷方式 应该来说 很多人都做过,我们就来看一下基本的快捷方式 是怎么实现的,会有什么问题?
首先 肯定要获取权限:
<!-- 添加快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 移除快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<!-- 查询快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
然后定义一下我们要发起的action:
//删除快捷方式的action
public static final String ACTION_REMOVE_SHORTCUT = "com.android.launcher.action.UNINSTALL_SHORTCUT";
//添加快捷方式的action
public static final String ACTION_ADD_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";
然后写2个方法即可:
//删除快捷方式
public static void removeShortcut(Context context, Intent actionIntent, String name) {
Intent intent = new Intent(ACTION_REMOVE_SHORTCUT);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
intent.putExtra("duplicate", false);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
context.sendBroadcast(intent);
}
//增加快捷方式
public static void addShortcut(Context context, Intent actionIntent, String name,
boolean allowRepeat, Bitmap iconBitmap) {
Intent addShortcutIntent = new Intent(ACTION_ADD_SHORTCUT);
// 是否允许重复创建
addShortcutIntent.putExtra("duplicate", allowRepeat);
// 快捷方式的标题
addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
// 快捷方式的图标
addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, iconBitmap);
// 快捷方式的动作
addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);
context.sendBroadcast(addShortcutIntent);
}
这种方法,大部分的手机都能正常使用。但是在某些国产手机上会有各种各样的问题。比如hw的手机这样做就完全无效。
小米的手机 无法重复创建快捷方式等。那现在看看 有没有什么方法 能解决这些问题。
首先我们来看一张图:

这张图很清晰的告诉我们launcher这个应用下面 是有一个数据库的。
我们可以打开这个数据库 看看到底是什么?


你看这个就一目了然了,快捷方式 都是存在于这个表里面的!所以 我们除了发送广播 可以创建快捷方式以外,我们直接操作数据库也应该是可以创建快捷方式的。
但是我们要注意啊,各家的lanucher 都有很大不同的,我上面的截图 是用的模拟器,所以是官方的rom,那路径肯定就是常规的,但是深度定制的android系统
大家都知道各家lanucher都是自己在做,所以favorites 这张表的位置到底在哪里,这就是个问题了。我们需要先查找出来这张表到底在哪个位置才能好操作这个表,
要想知道这个表在哪个位置,我们首先要知道 对于这个rom来说,是哪个lanucher在启作用?包名是什么?
//此函数返回当前rom下的lanucher的包名
private String getCurrentLanucherPackageName(Context context)
{
//这个intent很好理解 就是启动lanucher的intent
Intent intent=new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
//getPackageManager().resolveActivity 这个函数就是查询是否有符合条件的activity的
ResolveInfo res=context.getPackageManager().resolveActivity(intent,0);
//为避免空指针 我们要判定下空,虽然你我都知道这种情况不会发生
if(res==null||res.activityInfo==null)
{
return "";
}
return res.activityInfo.packageName;
}
有些人可能对于4-5行还是理解不了,为什么这个相当于是启动lanucher的intent 其实很简单,我们在android studio里 run一个app的时候,我们通常都能看到下面这个界面:

你看android studio 实际上安装完我们的应用以后 也是通过 这个intent来启动手机里的lanucher 然后让lanucher来运行我们的app,因为studio也不知道你手机里的lanucher到底是哪个
所以只能用intent来完成,这也就是上述代码能必定成功运行的原因!否则的话 android studio 就无法把你的app run进去了~~
当然了你也可以进入shell ,打ps 命令看看到底是不是有这个 包名的 进程在 运行中~~
好 拿到了我们的lanucher的包名,下面一步就是去我们的包名下 操作那个数据库即可了。那显然这个步骤 最合适的就是contentprovider来操作了。
//此函数返回 要查找的permission的 provider的 authority
private String getAuthorityFromPermission(Context context, String permission) {
//返回安装的app的 provider的信息
List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
//遍历获取到的安装包的信息
for (PackageInfo pack : packs) {
//每个安装包提供的provider 都在这个数组里面
ProviderInfo[] providers = pack.providers;
if (providers != null) {
//遍历每个provider 看需要的权限是否与我们传进来的权限参数相等
for (ProviderInfo providerInfo : providers) {
if (permission.equals(providerInfo.readPermission) || permission.equals(providerInfo.writePermission)) {
return providerInfo.authority;
}
}
}
}
return "";
}
private String getAuthorityFromPermissionDefault(Context context) {
return getAuthorityFromPermission(context, "com.android.launcher.permission.READ_SETTINGS");
}
private Uri getUriFromLauncher(Context context) {
StringBuilder uriStrBuilder = new StringBuilder();
//为了速度考虑,这里我们先查找默认的 看是否能查找到 因为多数手机的rom还是用的默认的lanucher
String authority = getAuthorityFromPermissionDefault(context);
//如果找不到的话 就说明这个rom一定是用的其他的自定义的lanucher。那就拼一下 这个自定义的lanucher的permission再去查找一次
if (authority == null || authority.trim().equals("")) {
authority = getAuthorityFromPermission(context,getCurrentLanucherPackageName(context) + ".permission.READ_SETTINGS");
}
uriStrBuilder.append("content://");
//如果连上面的方法都查找不到这个authority的话 那下面的方法 就肯定查找到了 但是很少有情况会是如下这种
//多数都是else里面的逻辑
if (TextUtils.isEmpty(authority)) {
int sdkInt = android.os.Build.VERSION.SDK_INT;
if (sdkInt < 8) { // Android 2.1.x(API 7)以及以下的
uriStrBuilder.append("com.android.launcher.settings");
} else if (sdkInt < 19) {// Android 4.4以下
uriStrBuilder.append("com.android.launcher2.settings");
} else {// 4.4以及以上
uriStrBuilder.append("com.android.launcher3.settings");
}
} else {
uriStrBuilder.append(authority);
}
uriStrBuilder.append("/favorites?notify=true");
return Uri.parse(uriStrBuilder.toString());
}
好,到这里 我们就能拿到所有rom 任意一款手机的 快捷方式 那张数据库表对应的uri了。
那到这里应该来说问题就基本解决了,你所有对快捷方式的操作 都可以直接通过这个uri来进行,无非就是一些crud的拼装。
再也不需要经过广播 那一道程序了,但是这里要注意的是 这种方法通常耗时都比较久,根据手机的性能的不同 200ms-600ms 才能完成uri的查找。所以记得做一下异步处理。
并且所有你对lanucher的 需求 都可以这么来做,比方说有些功能 在使用原生lanucher的手机上使用正常,在小米 华为 oppo使用不正常了,你就去找出来那个不正常的rom
的lanucher的 包名,然后找出他provider需要的权限,然后在你的manifest里 直接加权限 应该就可以正常使用了。第三方lanucher 引起的bug 基本上都可以通过这个方案
来解决。
Android 适配多种ROM的快捷方式的更多相关文章
- Android开发中适配多种 ROM 的快捷方式是如何实现的?
在安卓开发中,要提高开发效率,掌握一些快捷方式是必不可少的,特别是对于android入门阶段的童鞋而言,非常重要.今天小编在安卓开发教程网站上,搜罗了一些常用的Android 适配多种 ROM 的快捷 ...
- Android创建和删除桌面快捷方式
有同学方反馈创建快捷方式后,点击快捷方式后不能启动程序或者提示"未安装程序",貌似是新的rom在快捷方式这块做过修改(由于此文是11年5月所出,估计应该是2.0或2.1的rom), ...
- Android 适配知识点
转载:https://gold.xitu.io/post/58451c1d8e450a006c0f1c74 支持多种屏幕 Android 可在各种具有不同屏幕尺寸和密度的设备上运行.对于 应用,And ...
- Android 通过程序添加桌面快捷方式
原理:通过代码向 Launcher 中的广播接收者发送广播来创建快捷图标. 首先要声明的权限是: <!--添加图标的权限--> <uses-permission android:na ...
- Android中为APP创建快捷方式的原理(自己的理解)
我们首先来看Android中为APP创建快捷方式的原理: 从图上可以看出,Android大致分7步完成快捷方式的创建: 第一步:Android系统的launcher程序会调用它的pickShortcu ...
- Android适配难题全面总结
支持多种屏幕 Android 可在各种具有不同屏幕尺寸和密度的设备上运行.对于 应用,Android 系统在不同设备中提供一致的开发环境, 可以处理大多数工作,将每个应用的用户界面调整为适应其显示的 ...
- RomUtil【Android判断手机ROM,用于判断手机机型】
参考资料 Android判断手机ROM 正文 有时候需要判断手机系统的ROM,检测ROM是MIUI.EMUI还是Flyme,可以使用getprop命令,去系统build.prop文件查找是否有对应属性 ...
- Android 适配(一)
一.Android适配基础参数 1.常见分辨率(px) oppx 2340x1080 oppR15 2280x1080 oppor11sp 2160*1080 ...
- Android Studio 之 ROM【1】, Entity,Dao,Database
Android Studio 之 ROM, Entity,DAO,DataBase 1.Entity 实体类 package com.example.roombasic; import android ...
随机推荐
- Jmeter之Bean shell使用(二)
上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean shell,本文是对上文的一个补充,主要总结下常用的几种场景和方法,相信这些基本可以涵盖大部分的需求.本节内容如 ...
- php用fsockopen实现post提交数据并获得返回数据
/** * 函数介绍: 用于post方式提交数据 * 输入参数: 完整url, 数据 * 返回值 : 接口返回值 */ function post_it($url, $data = '', $time ...
- CreateProcess启动隐藏的外部程序(其实就是CreateDesktop,然后指定STARTUPINFO.lpDesktop)
HDESK hDesk = CreateDesktop(_T("MyDesk"), NULL, NULL, 0, GENERIC_ALL, NULL); ASSERT(hDesk) ...
- [iOS]提交App报错ERROR ITMS -90207
前几天上传项目N多次,都跳出这个问题 甚是头痛,于是乎各种搜索 1. 第三方的info.plist里面Executable file这个要删除(自己的不能删哦) 2.检查一下用来做跳转到第三方应用的设 ...
- RHEL7服务管理
对于学习过红帽RHEL6的系统或已经习惯使用service.chkconfig等命令来管理系统服务的用户可能要郁闷了, 因为在红帽RHEL7系统中管理服务的命令变成了“systemctl”,但使用方法 ...
- 几百万的数据,mysql快速高效创建索引
有一个问题,一张表有3百万条记录,随着时间的增加,记录量会更多,此时查询速度很慢.在创建此表前没有未相应字段添加索引,所以此时需要为表添加索引.但是因为数据量大的原因,索引添加不成功,想了很多办法,终 ...
- SQL Server ->> 关于究竟ALTER INDEX ... REBUILD会不会导致改变索引选项和Filegroup的验证
其实之前做过类型的验证,不过影响不是特别深,只是记得不会改变DATA COMPRESSION,那今天再次遇到这个问题就再拿出来验证一下.随便写个脚本验证下.ALTER INDEX ... REBUIL ...
- Oracle在linux下的开机自启动(详细)转
linux下系统开机oracle自启动(方法一) ---加载为服务自启动.停止一.dbstart 及 dbshut 1. 修改Oracle系统配置文件:/etc/oratab,只有这样,Ora ...
- SQLite的介绍 操作Sqlite 具体实例
1.SQLite简介 SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入 式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能 ...
- SPOJ 1487 Query on a tree III(划分树)
题目链接:http://www.spoj.com/problems/PT07J/ 题意:给出一个有根树,1为根节点,每个节点有权值.若干询问,询问以u为根的子树中权值第K小的节点编号. 思路:DFS一 ...