Android 修改framework实现 全局唯一launcher
16lz
2021-01-23
在网上找了好久唯一launcher的实现方式,发现都是一同一个人写的,而且并没有实现这个功能,因为按照这个方式去做的话,当你按下HOME键还是出现了选择launcher的对话框,然后自己研究了一天,找到了最直接有效的而且是最简单的方法实现全局唯一launcher的功能:
修改frameworks\base\core\java\android\content\pm\PackageParser.java,在parseIntent这个私有方法,因为APK在安装的时候会通过这个方法解析Manifest清单文件,然后将每个Activity的intent-filter保存在内存中,所以修改这个方法就相当于修改了内存的应用注册表的信息,也就是偷换概念的做法,等于是在安装的时候就把问题解决了,扼杀在萌芽状态:
修改部分为:
这里xxx随便你输入,例如你在你自己的launcher的Manifest的Activity里Intent-filter里加入:
那么在代码里修改的地方的xxx就替换成你自己起的名字
原理就是安装每个APK的时候 只要是launcher ,就把category是HOME的值改成x,只要是你的launcher就把category的值改成HOME,那么全局就只有你一个launcher了
这里是修改的部分:
/*************************************************************************************/ if(Intent.CATEGORY_HOME.equals(value)) { value = "x"; } else if((Intent.CATEGORY_HOME + ".xxx").equals(value)) { value = Intent.CATEGORY_HOME; } /*************************************************************************************/
使用这种方法修改时必须确保你的launcher被安装了或者放在了syste/app下了且Manifest的Activity里的intent-filter为android.category.HOME.xxx
具体的原理请参考我的另外一篇博客:http://blog.csdn.net/zhbinary/article/details/7353739
修改frameworks\base\core\java\android\content\pm\PackageParser.java里的parseIntent方法
private boolean parseIntent(Resources res, XmlPullParser parser, AttributeSet attrs, int flags, IntentInfo outInfo, String[] outError, boolean isActivity) throws XmlPullParserException, IOException { TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestIntentFilter); int priority = sa.getInt( com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) { Log.w(TAG, "Activity with priority > 0, forcing to 0 at " + mArchiveSourcePath + " " + parser.getPositionDescription()); priority = 0; } outInfo.setPriority(priority); TypedValue v = sa.peekValue( com.android.internal.R.styleable.AndroidManifestIntentFilter_label); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { outInfo.nonLocalizedLabel = v.coerceToString(); } outInfo.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); sa.recycle(); int outerDepth = parser.getDepth(); int type; while ((type=parser.next()) != parser.END_DOCUMENT && (type != parser.END_TAG || parser.getDepth() > outerDepth)) { if (type == parser.END_TAG || type == parser.TEXT) { continue; } String nodeName = parser.getName(); if (nodeName.equals("action")) { String value = attrs.getAttributeValue( ANDROID_RESOURCES, "name"); if (value == null || value == "") { outError[0] = "No value supplied for "; return false; } XmlUtils.skipCurrentTag(parser); outInfo.addAction(value); } else if (nodeName.equals("category")) { String value = attrs.getAttributeValue( ANDROID_RESOURCES, "name"); if (value == null || value == "") { outError[0] = "No value supplied for "; return false; } XmlUtils.skipCurrentTag(parser); /*************************************************************************************/ if(Intent.CATEGORY_HOME.equals(value)) { value = "x"; } else if((Intent.CATEGORY_HOME + ".xxx").equals(value)) { value = Intent.CATEGORY_HOME; } /*************************************************************************************/ outInfo.addCategory(value); } else if (nodeName.equals("data")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestData); String str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_mimeType, 0); if (str != null) { try { outInfo.addDataType(str); } catch (IntentFilter.MalformedMimeTypeException e) { outError[0] = e.toString(); sa.recycle(); return false; } } str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_scheme, 0); if (str != null) { outInfo.addDataScheme(str); } String host = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_host, 0); String port = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_port, 0); if (host != null) { outInfo.addDataAuthority(host, port); } str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_path, 0); if (str != null) { outInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); } str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_pathPrefix, 0); if (str != null) { outInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); } str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestData_pathPattern, 0); if (str != null) { outInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); } sa.recycle(); XmlUtils.skipCurrentTag(parser); } else if (!RIGID_PARSER) { Log.w(TAG, "Unknown element under : " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); } else { outError[0] = "Bad element under : " + parser.getName(); return false; } } outInfo.hasDefault = outInfo.hasCategory(Intent.CATEGORY_DEFAULT); if (false) { String cats = ""; Iterator it = outInfo.categoriesIterator(); while (it != null && it.hasNext()) { cats += " " + it.next(); } System.out.println("Intent d=" + outInfo.hasDefault + ", cat=" + cats); } return true; }
更多相关文章
- Android测试方法总结
- Android下生成core dump的方法
- ubuntu下eclipse Android ADT中SDK Manager中安装SDK失败的方法
- Android button原理 转载
- [置顶] Android 从硬件到应用:一步一步向上爬 4 -- 使用 JNI 方法
- Android异步加载图像小结(含线程池,缓存方法)[转]
- TextView支持的XML属性及相关方法
- 详解Android应用中使用TabHost组件进行布局的基本方法