将SystemUI导入AS编译运行
前期准备
以Android9.0源码(我这里用的是MT2712,win10环境,AS 4.1.3)为例
首先需要将源码进行一次编译,因为导出的SystemUI之后会引入一些编译后生成的库。
SystemUI代码路径为mt2712/frameworks/base/packages/SystemUI
将SystemUI代码拉到本地,删除代码中test和example相关目录 即删除shared/tests/、plugin/ExamplePlugin/和tests/三个目录。
同样的,将mt2712/frameworks/base/packages/SettingsLib、package/service/Car/car_lib和framework/support/car下拉到本地,删除其中的test目录。
SystemUI项目搭建
创建SystemUI项目
使用AS创建一个包名为com.android.systemui的No Activity项目 将SystemUI目录中的AndroidManifest.xml、Android.mk文件、res、res-keyguard和src目录下的所有文件移到刚创建的app目录的的src/main/java目录下,移动完目录结构如下:
- app
- src
- main
- java
- com.android.keyguard
- com.android.systemui
- res
- res-keyguard
- Android.mk
- AndroidManifest.xml
- java
- main
- src
在build.gradle文件内添加
1
2
3
4
5
sourceSets {
main {
res.srcDirs += "src/main/res-keyguard"
}
}
引用res-keyguard目录下的资源
创建Module
根据SystemUI源代码目录下的AndroidManifest.xml文件数量可以看出部分需要创建的Module(library形式的),我这里需要创建两个:
- shared:com.android.systemui.shared
- plugins:com.android.systemui.plugins
此外还有两个需要创建
- settingsLib:com.android.settingslib
- car_support:androidx.car
- 删除Module中src目录下的自动生成的目录(如test)
- 将SystemUI/shard、SystemUI/plugin、SettingsLib和car目录中的AndroidManifest.xml和Android.mk文件(没有则不用)和src目录下的所有文件移到对应Module的src/main/java目录下。
移动完毕后得到的目录结构如下(只列出了转移的文件):
- plugin
- src
- main
- java
- com.android.systemui.plugins
- Android.mk
- AndroidManifest.xml
- java
- main
- src
- shared
- src
- main
- java
- com.android.systemui.shared
- Android.mk
- AndroidManifest.xml
- java
- main
- src
- SettingsLib
- src
- main
- java
- com.android.systemui.shared
- res
- Android.mk
- AndroidManifest.xml
- java
- main
- src
- car_support
- src
- main
- java
- androidx.car
- res
- AndroidManifest.xml
- java
- main
- src
SystemUI库的引入
Android.mk中的库
下面是plugin和shared的Android.mk文件:
########### plugin Android.mk ###########
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
....
LOCAL_MODULE := SystemUIPluginLib
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
....
########### shared Android.mk ###########
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
....
LOCAL_MODULE := SystemUISharedLib
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_JAR_EXCLUDE_FILES := none
include $(BUILD_STATIC_JAVA_LIBRARY)
....
可以看出plugin和shared分别产生SystemUIPluginLib和SystemUISharedLib库。这两个库会被SystemUI所使用到。因为我们已经将这两部分以Module形式提出,所以直接在SystemUI的build.gradle中引入即可。
1
2
implementation project(':plugin')
implementation project(':shared')
根据Android.mk文件中LOCAL_STATIC_ANDROID_LIBRARIES、LOCAL_STATIC_JAVA_LIBRARIES和LOCAL_JAVA_LIBRARIES属性,可以了解到SystemUI引用到了哪些库,然后需要将这些库都找到放入app/libs目录下,然后在build.gradle文件中引入。
其中v4、v7、v14、v17的库可以先不引入,之后会将SystemUI中使用到这些库转成AndroidX的库,不引入可以减少一些麻烦。
SystemUI根目录Android.mk文件资源相关内容和对应的jar包如下:
# LOCAL_STATIC_ANDROID_LIBRARIES 里面引用到的库,大部分都可以在
# platform\out\soong\.intermediates\prebuilts\sdk\current目录下找到
# 比如android-support-car,对应的就是platform\out\soong\.intermediates\prebuilts\sdk\current\support\android-support-car\android_common\turbine-combined\android-support-car.jar
LOCAL_STATIC_ANDROID_LIBRARIES := \
SystemUIPluginLib \ # 对应plugin Module
SystemUISharedLib \ # 对应shared Module
android-support-car \ # android-support-car.jar
android-support-v4 \ # android-support-v4.jar
android-support-v7-recyclerview \ # android-support-v7-recyclerview.jar
android-support-v7-preference \ # 之后以此类推
android-support-v7-appcompat \
android-support-v7-mediarouter \
android-support-v7-palette \
android-support-v14-preference \
android-support-v17-leanback \
android-slices-core \
android-slices-view \
android-slices-builders \
android-arch-core-runtime \
android-arch-lifecycle-extensions \
# LOCAL_JAVA_LIBRARIES 里面的jar,是只在编译的时候引用即可,不需要打包进apk
# 这些jar是系统本身的jar,所以我们build.gradle以compileOnly方式引用
LOCAL_JAVA_LIBRARIES := telephony-common \
android.car
这些库中有一些是必须引入的,下方列出了库和其在源码中对应的jar包路径
导入framework.jar
framework.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\framework_intermediates\classes.jar
将其放入app/libs文件目录下,然后在根目录build.gradle在allproject下添加
1
2
3
tasks.withType(JavaCompile) {
options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\framework.jar')
}
在app、shared、plugin和SettingsLib,car_support目录下的build.gradle下添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
preBuild {
doLast {
def imlFile = file(project.name + ".iml")
println('Change ' + project.name + '.iml order')
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
parsedXml.component[1].remove(jdkNode)
def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
new groovy.util.Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
} catch (FileNotFoundException e) {
// nop, iml not found
}
}
}
这样就能优先使用我们导入的framework.jar
导入telephony-common.jar
telphont-common.jar 文件路径为:out/target/common/obj/JAVA_LIBRARIES/telephony-common_intermediates/classes-header.jar
导入core-libart.jar
core-libart.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\core-libart_intermediates\classes.jar
导入core-oj.jar
core-oj.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\core-oj_intermediates\classes.jar
导入car-lib.jar
car-lib.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\android.car_intermediates\classes.jar
导入android-slices-view.jar
android-slices-view.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\android-slices-view_intermediates\classes.jar
导入android-slices-builders.jar
android-slices-builders.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\android-slices-builders_intermediates\classes.jar
导入android-slices-view.jar
android-slices-view.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\android-slices-view_intermediates\classes.jar
导入systemui-tags.jar
systemui-tags.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\SystemUI-tags_intermediates\classes.jar
导入systemui-proto.jar
systemui-proto.jar 文件路径为:out\target\common\obj\JAVA_LIBRARIES\SystemUI-proto_intermediates\classes.jar
最后贴上我个人引入
常见错误
Found item Attr/longIntent more than one time
删除xml中重复的定义,非常多,需要花些时间。
AAPT: warn: multiple substitutions specified in non-positional format
将%s 改为 %1$s
AAPT: error: resource previously defined here.
文件中定义的属性与系统的属性值重名了,删掉即可。
AAPT: error: resource (color/dimen)/xxxxx (aka com.android.systemui:(color/dimen)/xxxx) not found.
在源码中找到对应的color值,写入res/values/colors.xml或者dimens.xml中中。
Error:Could not resolve all dependencies for configuration ‘:app:debugRuntimeClasspath’
gradle版本改成其他版本,我这里Android9.0,从4.1.3改为3.6.0就可以编译通过了。
1
2
3
classpath "com.android.tools.build:gradle:4.1.3"
->
classpath "com.android.tools.build:gradle:3.6.0"
程序包android.support.annotation、android.arch.lifecycle不存在等问题
可以尝试将这些包转成androidx,systemui项目和SettingsLibMoudle都有部分需要转换,可以通过AS的Refactor->Migrate to AndroidX转换。
程序包libcore.util不存在
这个可以直接取消引用,对应调用方法返回值设置为null就可以了,如果有用到就要去找对应的库。
AAPT: error: resource android:dimen/notification_extra_margin_ambient not found.
类似以下这种资源在framework/core/res/res/values/dimens.xml文件内的情况:
1
2
3
4
# 引用非 public 资源文件 (没在 public.xml 中声明的资源)
# xml: @*android:<resource_type>/<resource_name>
# code: com.android.internal.R.<resource_type>.<resource_name>
<dimen name="group_overflow_number_extra_padding_dark">@*android:dimen/notification_extra_margin_ambient</dimen>
将每个模块的 build.grale 中属性配置为当前 API 级别
1
2
compileSdkVersion 28
buildToolsVersion '28.0.1'
AAPT: error: duplicate value for resource ‘attr/xxxx’ with config ‘’.
删除attr.xml文件中对应的定义即可
Duplicate class android.xxx.xxxx found in modules
引入的jar包存在重复的类,删除重复的jar包
style attribute ‘attr/passwordStyle (aka com.android.systemui:attr/passwordStyle)’ not found.
在attrs.xml中添加对应的属性,例:
1
2
// 对应的fromat要对应
<attr name="passwordStyle" format="reference" />
resource style/PasswordTheme (aka com.android.systemui:style/PasswordTheme) not found.
与上面的问题类似,这个要在styles.xml中添加对应的style,例:
1
2
3
4
5
<style name="PasswordTheme" parent="Theme.SystemUI">
<item name="android:textColor">?attr/wallpaperTextColor</item>
<item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
<item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
</style>
no default product defined for resource com.android.systemui:string/power_remaining_duration_only_shutdown_imminent.
将values/string.xml中对应值的product改为default
import com.android.systemui.shared.recents.IOverviewProxy;/错误: 程序包IRecentsSystemUserCallbacks不存在
systemUI和module shared包内部有aidl文件,在src/main下创建aidl文件夹,将对应的文件按照源文件夹包名路径转过去即可,我这边转移后目录结构如下:
- app
- src
- main
- aidl
- com.android.systemui.recents
- IRecentsNonSystemUserCallbacks.aidl
- IRecentsSystemUserCallbacks.aidl
- com.android.systemui.recents
- java
- aidl
- main
- src
- shared
- src
- main
- aidl
- com.android.systemui.shared
- recents
- IOverviewProxy.aidl
- ISystemUiProxy.aidl
- system
- GraphicBufferCompat.aidl
- recents
- com.android.systemui.shared
- java
- aidl
- main
- src
找不到符号:Thread.getUncaughtExceptionPreHandler
找不到符号:Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler)/Thread.getUncaughtExceptionPreHandler()
1
2
Thread.getUncaughtExceptionPreHandler() -> Thread.getDefaultUncaughtExceptionHandler()
Thread.setUncaughtExceptionPreHandler -> Thread.setDefaultUncaughtExceptionHandler
找不到符号import com.xxxx.xxx
因为我们转成androidx,所以引入的类的包名会有一些变动,重新引入即可。
权限问题
没有对应的权限就加权限,有的话还报错就在引用位置加一个try-catch抛出错误