Android系统 设置第三方应用为默认Launcher实现和原理分析

简介: Android系统 设置第三方应用为默认Launcher实现和原理分析

前言

Android系统中,launcher是用户与系统交互的主要界面,它负责显示桌面、应用列表、小部件等内容。Android系统允许用户安装第三方的launcher应用,以替换系统自带的launcher。

但如何满足客制化需求让第三方的launcher应用成为默认的launcher呢?本文将从源码的角度,分析Android系统是如何处理launcher应用的启动和切换的,以及如何通过修改源码来实现设置第三方应用为默认launcher的功能。

launcher应用的启动和切换

在Android系统中,当用户按下Home键时,系统会发送一个包含Intent.CATEGORY_HOME类别的隐式Intent,该Intent的作用是启动一个能够显示主屏幕的Activity。系统会根据该Intent,在已安装的应用中查找匹配的Activity,并显示一个选择器让用户选择要启动的launcher应用。如果用户选择了某个应用,并勾选了“始终”选项,则该应用会被设置为默认的launcher,并保存在系统设置中。以后每次按下Home键时,系统都会直接启动该应用,而不再显示选择器(部分平台系统不会保存就算你选择了始终也,重启也会弹出选择)。

系统是如何保存和读取默认的launcher应用的呢?答案就在RootWindowContainer类中。该类是窗口管理服务(WindowManagerService)中最顶层的容器类,它负责管理所有显示内容(DisplayContent)和任务栈(TaskStack)。在该类中,有一个方法叫做resolveHomeActivity,它的作用是根据一个包含Intent.CATEGORY_HOME类别的Intent,解析出对应的ActivityInfo对象,并返回给调用者。该方法会首先从系统设置中读取默认的launcher组件名(ComponentName),如果存在,则直接使用该组件名创建一个显式Intent,并通过包管理服务(PackageManagerService)获取对应的ActivityInfo对象;如果不存在,则使用隐式Intent查询匹配的Activity,并返回第一个匹配结果(通常是系统自带的launcher)。

当用户在选择器中选择了某个launcher应用,并勾选了“始终”选项时,系统会调用ActivityManagerService中的setHomeActivity方法,将用户选择的launcher组件名保存在系统设置中。这样,下次再按下Home键时,就会直接启动该组件对应的Activity。

设置第三方应用为默认launcher

有了上面的分析,我们就可以知道如何通过修改源码来实现设置第三方应用为默认launcher的功能。我们只需要修改RootWindowContainer类中的resolveHomeActivity方法,让它不再从系统设置中读取默认的launcher组件名,而是从我们指定的地方获取。例如,我们可以使用一个系统属性(SystemProperty)来存储我们想要设置为默认launcher的应用包名(PackageName),然后在该方法中根据该包名查询匹配的Activity,并返回其ActivityInfo对象。这样,我们就可以通过修改系统属性来控制默认的launcher应用。

具体来说,我们可以按照以下步骤来修改源码:

vi frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

  1. RootWindowContainer类中导入以下几个类:
import android.os.SystemProperties;
import android.text.TextUtils;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
  1. resolveHomeActivity方法中添加以下代码:
// 从系统属性中获取Home包名
String homePackageName = SystemProperties.get("persist.home.package", null);
// 如果没有设置Home包名,则使用默认的"com.android.launcher3"
if (TextUtils.isEmpty(homePackageName)) {
    homePackageName = "com.android.launcher3"; // 默认launcher包名
}
try {
    Intent it = new Intent(Intent.ACTION_MAIN);
    List<ResolveInfo> list = AppGlobals.getPackageManager().queryIntentActivities(homeIntent,
            homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver()), ActivityManagerService.STOCK_PM_FLAGS, userId).getList();
    final int count = list.size();
    for (int i = 0; i < count; i++) {
        ResolveInfo r = list.get(i);
        if (homePackageName.equals(r.activityInfo.packageName)) {
            Slog.d(TAG, "3rd launcher: " + r.activityInfo.packageName + "@" + r.activityInfo.name);
            comp = new ComponentName(homePackageName, r.activityInfo.name);
            aInfo = r.activityInfo;
            break;
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}
if (aInfo == null) {
    // 如果指定的Home包名应用未安装或找不到指定的Activity,启动默认的Launcher
    PackageManager packageManager = mService.mContext.getPackageManager();
    homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
    comp = homeIntent.resolveActivity(packageManager);
    if (comp != null) {
        try {
            aInfo = packageManager.getActivityInfo(comp, flags);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
if (aInfo == null) {
    Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
    return null;
}
  1. 注释掉原来的代码:
/*@VisibleForTesting
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
    final int flags = ActivityManagerService.STOCK_PM_FLAGS;
    final ComponentName comp = homeIntent.getComponent();
    ActivityInfo aInfo;
    if (comp != null) {
        try {
            aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
        } catch (RemoteException e) {
            return null;
        }
    } else {
        ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(homeIntent,
                homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver()), flags, userId);
        if (info != null) {
            aInfo = info.activityInfo;
        } else {
            Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
            return null;
        }
    }
    aInfo = new ActivityInfo(aInfo);
    aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
    return aInfo;
}*/
  1. 重新编译并刷入系统 , 我的验证结果是 :
  • 如果默认没有预装第三方launcher , 则走默认launcher3 。
  • 如果装了第三方launcher 则走第三方的 , 并且按home和重启不会再次弹框。

总结

本文介绍了Android系统中launcher应用的启动和切换的原理,以及如何通过修改源码来实现设置第三方应用为默认launcher的功能。通过这个例子,我们可以了解Android系统中隐式Intent和显式Intent的区别,以及如何使用系统属性和包管理服务来控制应用的启动。

希望本文对你有所帮助,如果你有任何问题或建议,欢迎在评论区留言。谢谢!

相关文章
|
1月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
179 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
1月前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
56 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
3月前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
110 14
|
3月前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
3月前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
102 0
|
Android开发 iOS开发 C++
Flutter中设置Android的应用名称和图标(android,ios,web)
在前面的几期给大家介绍了flutter的安装以及一些简单的配置,还运行了helloword 那么接下来就带领大家了解如何设置应用名称以及图标
313 0
|
4月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。
|
1月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
65 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
2月前
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
111 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
24天前
|
安全 Android开发 iOS开发
escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
escrcpy 是一款基于 Scrcpy 的开源项目,使用 Electron 构建,提供图形化界面来显示和控制 Android 设备。它支持 USB 和 Wi-Fi 连接,帧率可达 30-120fps,延迟低至 35-70ms,启动迅速且画质清晰。escrcpy 拥有丰富的功能,包括自动化任务、多设备管理、反向网络共享、批量操作等,无需注册账号或广告干扰。适用于游戏直播、办公协作和教育演示等多种场景,是一款轻量级、高性能的 Android 控制工具。

热门文章

最新文章

  • 1
    Android历史版本与APK文件结构
  • 2
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 4
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 5
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
  • 6
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 8
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
  • 9
    Android实战经验之Kotlin中快速实现MVI架构
  • 10
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
  • 1
    【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
    66
  • 2
    android FragmentManager 删除所有Fragment 重建
    25
  • 3
    Android实战经验之Kotlin中快速实现MVI架构
    42
  • 4
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    42
  • 5
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    46
  • 6
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    158
  • 7
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    55
  • 8
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    73
  • 9
    Android历史版本与APK文件结构
    182
  • 10
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    54