1. 晋级编译环境

开发环境

预备Flamingo 或许最新Bate 版别的Android Studio
预备Android 14 的设备((https://developer.android.google.cn/about/versions/14/devices?hl=zh-cn))
gradle装备
classpath 'com.android.tools.build:gradle:8.0.0'
distributionUrl=https://services.gradle.org/distributions/gradle-8.0.0-bin.zip
设置Android 14 SDK
android {
  compileSdkPreview = "UpsideDownCake"
  ...
  defaultConfig {
    targetSdkPreview = "UpsideDownCake"
  }
}
生成BuildConfig和AIDL 相关文件
buildFeatures {
    buildConfig = true
    aidl = true
}
R文件传递
android.nonTransitiveRClass=false
View的id区别时运用Switc case
运用 if()else if() 替换 switch  case  或许在Gradle.properties中增加android.nonFinalResIds=false
设置命名空间:删去Manifest下的package标签,将包名信息增加到gradle的android途径下
android {
     namespace = "com.xx.xx"
 }
 项目中运用CompileOnly 编译的库需求在混杂文件中增加直接引证的类

TargetSdkVersion >=34的修正

对隐式 intent 和待处理 intent 的约束

关于以 Android 14 为方针渠道的运用,Android 会经过以下办法约束运用向内部运用组件发送隐式 intent:

  • 隐式 intent 只能传送到导出的组件。运用有必要运用显式 intent 传送到未导出的组件 带包名的去跳转,或将该组件符号为已导出。
  • 假如运用经过未指定组件或软件包的 intent 创立可变待处理 intent,体系现在会抛出反常。

这些改变可避免歹意运用拦截意在供运用内部组件运用的隐式 intent。

<activity
    android:name=".AppActivity"
    android:exported="false"> //false 不行导出 true可导出
    <intent-filter>
        <action android:name="com.example.action.APP_ACTION" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
Intent explicitIntent =new Intent("com.example.action.APP_ACTION")
//跳转不行导出,需求设置包名
explicitIntent.setPackage(context.getPackageName());
context.startActivity(explicitIntent);

在运转时注册的播送接收器有必要指定导出行为

在 Android 14 上,运转时经过 Context#registerReceiver() 动态注册播送接收器,需求设置符号 RECEIVER_EXPORTEDRECEIVER_NOT_EXPORTED ,标识是否导出该播送,避免运用程序呈现安全漏洞,假如注册的是体系播送,则不需求指定符号。

三方SDK兼容修正办法:

假如三方SDK适配困难能够先在Activity或许Application中复写播送注册办法,假如有未增加是否可导出符号能够手动增加上


@Override 
public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED或许Context.RECEIVER_NOT_EXPORTED); 
    }
@Override
public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, int flags) {
    Intent intent=null;
    try {
            boolean flagExported = (flags & Context.RECEIVER_EXPORTED) != Context.RECEIVER_EXPORTED;
            boolean flagNotExported = (flags & Context.RECEIVER_NOT_EXPORTED) != Context.RECEIVER_NOT_EXPORTE;
            if(!flagExported && !flagNotExported){
               intent = super.registerReceiver(receiver, filter, flags|Context.RECEIVER_EXPORTED或许Context.RECEIVER_NOT_EXPORTED);    
               return intent;
            }
        intent = super.registerReceiver(receiver, filter,flag);
    } catch (Throwable e) {
    }
    return intent;
}
。。。。。其他多参办法补上EXPORTED 参数

安全的动态代码加载(插件化/热更新)

new DexClassLoad(x,x,x,)
DexFile.loadFile(x)
都会抛反常

在动态文件(例如 DEX、JAR 或 APK 文件)打开并写入任何内容之前当即将其设为只读,插件化、热修复触及ClassLoad去加载代码的地方,假如文件有写权限会当即报错。

将新下载的文件特点修正成只读文件,假如是已存在的文件最好能够先删去然后重新下载而且设置只读权限。

public static void modifyFileOnlyRead(String apkPath) {
    if (Util.isAndroidU()) {
        try {
            File file = new File(apkPath);
            boolean b = file.setReadOnly();
            if (file.canWrite()) {
                Runtime.getRuntime().exec("chmod 400 " + apkPath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

压缩途径遍历

关于以 Android 14 为方针渠道的运用,Android 会经过以下办法避免 Zip 途径遍历漏洞:假如 Zip 文件条目名称包括“..”或以“/”开头,ZipFile(String)ZipInputStream.getNextEntry() 会抛出 ZipException

运用能够经过调用 dalvik.system.ZipPathValidator.clearCallback() 挑选停用此验证。

从后台发动Activity的附加约束

体系进一步约束了运用在后台发动 Activity 的时间:

  • 当运用运用 PendingIntent#send() 发送 PendingIntent 以及相似行为时,假如运用想要颁发其自己的后台 service 发动权限以发动 pending intent,则该运用现在有必要挑选参加一个 ActivityOptions,具体为带有 setPendingIntentBackgroundActivityStartMode(MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
  • 当一个可见运用运用 bindService() 绑定另一个在后台运转的运用的服务时,假如该可见运用想要将其自己的后台 activity 发动权限颁发绑定服务,则它现在有必要挑选参加 BIND_ALLOW_ACTIVITY_STARTS 标志。

发动前台服务有必要设置前台服务类型

假如有运用startForeground()
在清单文件中有必要要指定服务的前台类型,例如音频播映类的能够运用mediaPlayback

为了协助开发者更有目的地界说面向用户的前台服务,Android 10 在<service>元素内引入了android:foregroundServiceType特点。

假如您的运用以 Android 14 为方针渠道,则有必要指定适当的前台服务类型。与以前的 Android 版别一样,可组合运用多个类型。下面列出了可供挑选的前台服务类型:

  • camera
  • connectedDevice
  • dataSync
  • health
  • location
  • mediaPlayback
  • mediaProjection
  • microphone
  • phoneCall
  • remoteMessaging
  • shortService
  • specialUse
  • systemExempted

假如运用中的用例与这些类型均不相关,激烈建议您迁移逻辑以运用WorkManager或用户建议的数据传输作业。

Android 14 中新增了health, remoteMessaging, shortService, specialUsesystemExempted类型。

以下代码段提供了一个清单中的前台服务类型声明示例:

<manifest ...>
 <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
  <application ...>
   <service
     android:name=".MyMediaPlaybackService"
     android:foregroundServiceType="mediaPlayback"
     android:exported="false">
   </service>
  </application>
</manifest>

假如以 Android 14 为方针渠道的运用未在清单中界说给定服务的类型,体系会在调用startForeground()时引发MissingForegroundServiceTypeException

Open JDK 17

Android 14 将继续更新 Android 的中心库,以与最新 OpenJDK LTS 版别中的功用保持一致,包括合适运用和渠道开发者的库更新和 Java 17 言语支撑。

以下改变或许会影响运用兼容性:

  • 对正则表达式的更改:现在,为了更严厉地遵从 OpenJDK 的语义,不答应无效的组引证。您或许会看到 java.util.regex.Matcher 类抛出 IllegalArgumentException 的新情况,因而请务必测验运用中运用正则表达式的情形。如需在测验期间启用或停用此改变,请运用兼容性框架东西切换 DISALLOW_INVALID_GROUP_REFERENCE 标志。
  • UUID 处理:现在,验证输入参数时,java.util.UUID.fromString() 办法会履行更严厉的查看,因而您或许会在反序列化期间看到 IllegalArgumentException。如需在测验期间启用或停用此改变,请运用兼容性框架东西切换 ENABLE_STRICT_VALIDATION 标志。
  • ProGuard 问题:有时,在您测验运用 ProGuard 减缩、混杂和优化运用时,增加 java.lang.ClassValue 类会导致问题。问题源自 Kotlin 库,该库会根据 Class.forName("java.lang.ClassValue") 是否会返回类更改运转时行为。假如您的运用是根据没有 java.lang.ClassValue 类的旧版运转时开发的,则这些优化或许会将 computeValue 办法从派生自 java.lang.ClassValue 的类中移除。

Android 14 中有关约束非 SDK 接口的更新

非SDK API 表
(官网下载文件)

运用 Lint东西查看

TargetSdkVersion >=33的修正

默许回绝设定精确的闹钟

Android 14 开端 ,targetSdkVersion>=33的新装置用户 SCHEDULE_EXACT_ALARM 权限默许回绝,在运用

  • setExact()
  • setExactAndAllowWhileIdle()
  • setAlarmClock()

时,APP会抛出反常,可在调用上述办法之前运用 canScheduleExactAlarms()

判别是否有闹钟权限,而且设置AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 监听前台播送并对其做出正确反应 ,体系会在用户颁发权限时发送该播送。

三种种办法修正:

  1. 需求运用ACTION_REQUEST_SCHEDULE_EXACT_ALARM 这个Action跳转体系页面去手动敞开此权限

    1.         public static void openAlarmPage(Context context){
                  //可界说播送监听 SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED  是否敞开
                  Intent intent = new Intent();
                  intent.setAction(ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
                  context. startActivity(intent);
              }
      
  2. Menifest申明<uses-permission android:name="android.permission.USE_EXACT_ALARM" />这个一般权限不需求运转时恳求,但是需求留意隐私声明

  3. 无权限时运用 这个api AlarmManager.setExact(x,x,OnAlarmListener,x,x)在OnAlarmListenr中再次敞开定时

    1.  public void start () {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             alarmManager.setExact(xxx, xxx, "TAG", new AlarmManager.OnAlarmListener() {
                     @Override
                     public void onAlarm() {          
                         start();
                     }
                 }, xx);
                 }
             }
    

颁发对相片和视频的部分访问权限

只颁发所选中媒体文件的权限

针对Android 13 及以上用户 Android 14 以上新增的权限 READ_MEDIA_VISUAL_USER_SELECTED 仅答应颁发选中媒体文件的访问权限。如需求访问一切媒体文件需求同步恳求READ_MEDIA_IMAGESREAD_MEDIA_VIDEO .

TargetSdkVersion==xxx 不区别版别对一切运用的更改

TargetSdkVersion<23的运用无法在Android U上装置

安全性,下降低版别权限问题导致APP数据走漏,晋级TargetSdkVersion >=23

INSTALL_FAILED_DEPRECATED_SDK_VERSION: App package must target at least SDK version 23, but found 7

假如需求调试低版别Target的APP能够运用命令行装置

adb install --bypass-low-target-sdk-block app.apk

运用进入缓存时,上下文注册的播送将参加行列

运用进入缓存状况(例如进入后台) 上下文注册的播送会参加行列,等候运用退出缓存状况时,会一次性将多个在缓存行列的播送一次性发送, 存在播送合并的情况, 例如监听屏幕敞开/封闭/敞开/封闭, 运用只能承受敞开-封闭 中心的状况会丢失.,播送也或许由于体系原因会从缓存行列删去. 此项改变让播送接收变得不那么靠谱,或许会导致APP资源得不到毁掉引起内存走漏

运用只能停止自己的后台进程

从 Android 14 开端,当您的运用调用 killBackgroundProcesses() 时,该 API 只能停止您自己运用的后台进程。(影响第三方杀进程的运用例如(360手机卫兵))

用户能够封闭不行封闭的告诉

这项改变适用于经过 Notification.Builder#setOngoing(true)NotificationCompat.Builder#setOngoing(true) 设置 Notification.FLAG_ONGOING_EVENT 来阻止用户封闭前台告诉的运用。FLAG_ONGOING_EVENT 的行为已发生变化,运用户实际上能够封闭此类告诉。

在以下情况下,此类告诉仍不行封闭:

  • 当手机处于确定状况时
  • 假如用户挑选悉数清除告诉操作(有助于避免意外封闭)

此外,这一新行为不适用于以下用例中的不行封闭告诉:

  • 运用 MediaStyle 创立的告诉(notification.setStyle(ew NotificationCompat.MediaStyle()))

  • 安全和隐私用例的方针约束运用

  • 企业设备方针控制器 (DPC) 和支撑软件包

新增、改善功用

截屏监听

增加权限: 能够监听截屏但是截屏文件还需求运用常规办法自己获取

<uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />
final Activity.ScreenCaptureCallback screenCaptureCallback =
    new Activity.ScreenCaptureCallback() {
        @Override
        public void onScreenCaptured() {
            // Add logic to take action in your app.
        }
    };
@Override
protected void onStart() {
    super.onStart();
    // Pass in the callback created in the previous step
    // and the intended callback executor (e.g. Activity s mainExecutor).
    registerScreenCaptureCallback(executor, screenCaptureCallback);
}
@Override
protected void onStop() {
    super.onStop();
    unregisterScreenCaptureCallback(screenCaptureCallback);
}

制止当时ACtivity截屏能够增加下面的flag

activity.getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);

Path 途径可查询过程中的点位信息

Android 的 Path API 是一种强大且灵敏的机制,可用于创立和渲染矢量图形,能够描边或填充途径,根据线段、二次曲线或立方曲线构建途径,履行布尔运算以获取更复杂的形状,或同时履行一切这些操作。但是无法了解 Path 方针中实际包括的内容;该方针的内部信息在创立后关于调用方是不透明的。

如需创立 Path,能够调用 moveTo()lineTo()cubicTo() 等办法来增加途径片段。但无法问询该途径有哪些片段,因而有必要在创立时保留该信息。

从 Android 14 开端,能够查询途径以了解其内部内容。首要,需求运用 Path.getPathIterator API 获取 PathIterator 方针:


Path path = new Path();path.moveTo(1.0F, 1.0F);path.lineTo(2.0F, 2.0F);path.close();PathIterator pathIterator = path.getPathIterator();

接下来,能够调用 PathIterator 逐一遍历片段,并检索每个片段的一切必要数据。以下示例运用了 PathIterator.Segment 方针,它会打包数据:


while (pathIterator.hasNext()) {    PathIterator.Segment segment = pathIterator.next();    Log.i(LOG_TAG, "segment: " + segment.getVerb() + ", " + segment.getPoints());}

PathIterator 还有一个非分配版 next(),能够在其间传入缓冲区来保存点数据。

查询 Path 数据的一个重要用例是插值。例如,大家或许想在两个不同的途径之间增加动画(或变形)。为了进一步简化该用例,Android 14 针对 Path 还有一个新的 interpolate() 办法。假设两个途径具有相同的内部结构,interpolate() 办法会运用该插值成果创立一个新的 Path。以下示例返回了一个形状介于 pathotherPath 之间的一半(线性插值为 0.5)的途径:


Path interpolatedResult = new Path();
if (path.isInterpolatable(otherPath)) {    
    path.interpolate(otherPath, 0.5F, interpolatedResult);
}

单运用言语偏好/语法优化/地区偏好

功用和 API 概览 | Android 开发者 | Android Developers (google.cn)

位置权限新增标签描绘

权限弹窗是会显示描绘信息,需求在清单文件中增加

在运用的资源目录/etc/ASL/asl-locations.xml新增装备,
<ASL-locations>
<ASL  package="com.xx.xx">【Path to ASL XML} </ASL>
</ASL-locations>

新增用户初始化Job权限RUN_USER_INITIATED_JOBS

Android 14 引入了android.permision.RUN_USER_INITIATED_JOBS权限,答应一个运用履行用户初始化Job权限,此权限能够被用手动封闭或许被体系撤销,运用需求targestsdk晋级到U后来恳求此权限

新增唤醒屏幕权限

Android 14 引入了android.permision.TURN_SCREEN_ON权限,方针渠道为Android 14及以上的运用运用唤醒屏幕时,需求在AndroidManifest文件中装备这个权限。别的唤醒屏幕权限有一个对应的appops权限AppOpsManager.OP_TURN_SCREEN_ON,这个权限在Android T上是默许敞开,在Android U上对方针渠道为Android 14及以上的运用默许封闭。

不恳求权限调用下面API 没有效果无法唤醒屏幕

PowerManager powerManager = (PowerManager) Context.getSystemService(
Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "testName");
wakeLock.acquire(3000)

字体扩大能够到200%

功用和 API 概览 | Android 开发者 | Android Developers (google.cn)