Android14源码移植到Android16的应用报错分析说明
Android14源码移植到Android16的应用报错分析说明
文章目录
- Android14源码移植到Android16的应用报错分析说明
- 一、前言
- 二、具体分析说明
- 1、分析过程
- 2、Android.bp属性分析修改
- 3、某些具体代码规范修改示例
- (1)未使用的方法和变量报错
- (2)未定义final报错
- (3)未定义static
- (4)发送广播报错
- (5)注释
- 三、其他
- 1、报错小结
- 2、Android命名规范
- 3、Android16 应用代码新特性
- 4、Android.bp其他属性规范代码方式示例
- (1)通过 `errorprone` 配置强制 Java 代码规范
- (2)通过 `lint` 配置强制 Android 特定规范
- (3)通过 `javacflags` 配置基础 Java 编译规范
一、前言
最近移植Android14的应用源码到Android16上面发现有报错。
移植的部分源码是系统Bluetooth应用的修改代码;普通的系统应用源码修改好像是没这些报错的。
主要报错内容有:未使用final,方法或者变量未使用,注释代码不正确等等编译异常。
这个些问题编译Error异常,是必须处理的,不能跳过,要适配代码或者环境。
为啥Android16中会报错?Android14的源码没有报错?
下面进行简单分析介绍,后续Android新版本源码可能会遇到相关的问题,可以参考修改。
二、具体分析说明
1、分析过程
不同源码的SKD版本肯定不同,难道是因为SDK版本问题?
但是思索过后发现,应该不是SDK问题,像是强制代码规范问题;
估计和Java版本的jdk有关?
//Android14的系统源码的Java版本默认是17
//jdk 17 没有强制代码规范问题
Android14_OS/release$ java --version
openjdk 17.0.4.1 2022-08-12
OpenJDK Runtime Environment Android_PDK (build 17.0.4.1+0-9205083)
OpenJDK 64-Bit Server VM Android_PDK (build 17.0.4.1+0-9205083, mixed mode, sharing)
Android14_OS/release$ //Android15和Android16的系统源码的Java版本默认是17
//这个jdk 21是问题的?
Android16_OS/release$ java --version
openjdk 21.0.1 2023-10-17
OpenJDK Runtime Environment Android_PDK (build 21.0.1+-11233762)
OpenJDK 64-Bit Server VM Android_PDK (build 21.0.1+-11233762, mixed mode, sharing)
Android16_OS/release$
但是Java规范应该很早以前就有了,所以不一定是Java版本问题。
大概猜测是Android.bp定义的某个属性字段的区别。
通过多个属性对比和修改,发现了确实是Android16某个属性导致代码强制规范。
相关的属性是:defaults: [“bluetooth_framework_errorprone_rules”],
2、Android.bp属性分析修改
不同源码定义的default规则代码有点差异:
//Android14 Bluetooth:
android_app {name: "Bluetooth",defaults: ["bluetooth-module-sdk-version-defaults"],//AN15 Bluetooth:
android_app {name: "Bluetooth",defaults: ["bluetooth_framework_errorprone_rules"],//AN16 Bluetooth:android_library {name: "BluetoothLib",
- defaults: ["bluetooth_framework_errorprone_rules"],manifest: "LibAndroidManifest.xml",
上面是Android14-16的 Bluetooth 应用源码 packages\modules\Bluetooth\android\app\Android.mk 的部分区别。
可以看到Android14 定义的是bluetooth-module-sdk-version-defaults;
Android15和Android16 定义的是"bluetooth_framework_errorprone_rules;
具体的强制规范的内容,这里不进行探讨和研究。
Android16 在app编译中未定义default,但是他加载的默认库,是定义的default。
总之问题是找到了,如何修改?
尝试了把Android14的default放到16中编译,发现会编译失败,估计不兼容。
解决方法:
可以把 defaults 的整个属性去掉就可以规避这些编译报错。
因为我们自研的很多系统应用都是没加这个defaults属性的;
很少对于系统代码会进行强制规范。
但是平时开发的代码还是要进行代码规范比较好。
如果不想修改上面的Android.bp文件,可以慢慢修改代码规范问题,就可以编译通过了。
3、某些具体代码规范修改示例
(1)未使用的方法和变量报错
代码:
final int confirmIndex = cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION);
上面是普通定义的代码。
报错:
packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java:329: error: [UnusedVariable] The local variable 'confirmIndex' is never read.
final int confirmIndex = cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION);
解决:
删除或者暂时注释无用代码。
其他的方法或者方法内的变量未使用也是爆类似的错误。
(2)未定义final报错
代码:
private String TAG = "NotifyDialogManager";
报错:
error: [FieldCanBeFinal] This field is only assigned during initialization; consider making it final
解决:
private static final String TAG = "NotifyDialogManager"; //最后是加 static final
如果不需要暴露可以不加static
(3)未定义static
代码:
WindowManager.LayoutParams createLayoutParams() { }
private void updateCompletedNotification() { }
报错:
error: [MethodCanBeStatic] A private method that does not reference the enclosing instance can be static(see https://errorprone.info/bugpattern/MethodCanBeStatic)Did you mean 'static WindowManager.LayoutParams createLayoutParams() {'?
packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java:487: error: [MethodCanBeStatic] A private method that does not reference the enclosing instance can be staticprivate void updateCompletedNotification() {^(see https://errorprone.info/bugpattern/MethodCanBeStatic)Did you mean 'private static void updateCompletedNotification() {'?
解决: 添加static
(4)发送广播报错
这个好像是一个蓝牙的系统的广播,并不是所以的发送广播都会有这个报错。
代码:
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_DECLINE));
报错:
error: [AndroidFrameworkRequiresPermission] Failed to resolve broadcast intent action for validation
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT));
解决:
方式一:
在方法请添加备注进行规避:@SuppressLint("MissingPermission")方式二:
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT),"com.android.permission.RECEIVE_ACCEPT" // 与定义的权限一致
);方式三:
Intent intent = new Intent(baseIntent);
intent.setAction(Constants.ACTION_ACCEPT);
// 显式指定目标接收器的类名(确保接收器在当前应用中)
intent.setComponent(new ComponentName(mContext, YourReceiver.class));
mContext.sendBroadcast(intent); // 此时无需依赖 Action 匹配,Lint 不会报错方式四:
如果是本应用接收,使用本地广播
import androidx.localbroadcastmanager.content.LocalBroadcastManager;LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT));
需要注意的是,发送这里修改成本地广播,注册监听的地方也要修改成本地广播的方式进行监听,无法会监听不到。
(5)注释
代码:
private test () {/** test message**/String tast = "a";
}
报错:
error: [NotJavadoc] Avoid using `/**` for comments which aren't actually Javadoc./** test message**/^(see https://errorprone.info/bugpattern/NotJavadoc)Did you mean '/* test message**/'?
解决:
把代码内部注释/** --- **/ 替换成 /* -- */
第一种注释的方法前面的说明,第二种注释才是代码方法内的片段注释,主要用于多行说明的注释。
还有其他一些报错,根据报错内容进行修改就OK的,一般不会太难。
三、其他
1、报错小结
这里的报错都是Java的代码规范报错;有部分可能是安全规范报错;
后面新版本的Android源码可能会更多系统应用有代码规范的要求。
平时开发的时候多注意规范代码就可以避免大部分的问题了。
2、Android命名规范
Android程序开发中,使用规范的命名有益于程序的开发和后期阅读。
本文主要对Android程序包名的定义做详细介绍,并附带一些简单的命名规则:
https://blog.csdn.net/wenzhi20102321/article/details/61650405
3、Android16 应用代码新特性
Android 16 相对于 Android 15 和 14,在系统行为、[API 接口](https://so.csdn.net/so/search?q=API 接口&spm=1001.2101.3001.7020)、权限模型、性能优化等方面存在多处代码级差异,这些差异直接影响应用的兼容性和功能实现。
以下从核心场景对比具体代码变化,有兴趣的看看:
https://blog.csdn.net/wenzhi20102321/article/details/152091011
4、Android.bp其他属性规范代码方式示例
Android.bp除了上面的defaults,还是其他代码属性也是有规范代码的作用的,
但是不一定有用,需要自己验证编译,这里经供参考:
(1)通过 errorprone
配置强制 Java 代码规范
java_library { // 或 android_library、java_binary 等模块类型name: "my_module",srcs: ["src/**/*.java"],// 配置 ErrorProne 静态检查errorprone: {javacflags: [// 1. 强制文档注释规范(如避免类似 Javadoc 但格式错误的注释)"-Xep:AlmostJavadoc:ERROR",// 2. 强制处理空指针风险(禁止对 @Nullable 变量直接调用方法)"-Xep:NullAway:ERROR","-XepOpt:NullAway:AnnotatedPackages=com.example", // 指定检查的包// 3. 禁止未使用的变量、参数(减少冗余代码)"-Xep:UnusedVariable:ERROR","-Xep:UnusedParameter:ERROR",// 4. 禁止自动装箱/拆箱的冗余操作(如 Integer.valueOf(1) 可简化为 1)"-Xep:RedundantBoxing:ERROR",// 5. 禁止使用过时 API(强制替换为新 API)"-Xep:DeprecatedApi:ERROR",// 6. 强制 equals() 与 hashCode() 成对重写(避免集合操作异常)"-Xep:EqualsHashCode:ERROR",// 7. 禁止字符串常量拼接(如 "a" + "b" 应直接写 "ab")"-Xep:StringEquality:ERROR",],},
}
(2)通过 lint
配置强制 Android 特定规范
android_library {name: "my_android_module",srcs: ["src/**/*.java"],resource_dirs: ["res"],// 配置 Android Lint 检查lint: {// 1. 开启严格模式:所有 Lint 警告视为错误(阻断构建)strict: true,// 2. 仅启用指定的检查项(按需添加,更精准)checks: ["UnusedResources", // 禁止未使用的资源(drawable、string等)"HardcodedText", // 禁止硬编码文本(强制使用 string.xml)"LogUsage", // 禁止在正式代码中使用 Log(需替换为日志框架)"ToastLength", // 禁止 Toast 时长使用 LENGTH_LONG(避免用户体验问题)"AppCompatMethod", // 强制使用 AppCompat 兼容方法(如 getSupportActionBar())],// 3. 排除特定检查项(可选,在 strict=true 时临时放宽)disable: ["TypographyDashes"], // 暂时允许连字符不规范// 4. 配置检查的严重级别(如将某检查项设为错误)error: ["HardcodedText"], // 即使 strict=false,也将硬编码文本设为错误},
}
(3)通过 javacflags
配置基础 Java 编译规范
java_library {name: "my_module",srcs: ["src/**/*.java"],// 基础 Java 编译规范javacflags: ["-Werror", // 将所有编译器警告视为错误(强制修正所有警告)"-Xlint:unchecked", // 检测未检查的类型转换(泛型相关)"-Xlint:deprecation", // 检测使用过时 API 的警告"-Xlint:rawtypes", // 禁止使用原始类型(如 List 而非 List<String>)],
}
不同的源码或者不同Android版本对于规范的属性可能不一定完全通用;
一般可以借鉴其他的系统源码应用的Android.bp规则进行对比修改。