CLOUSD
Mở tài khoản
Kiểm thử

Test ứng dụng trên các phiên bản Android khác nhau

Theo từng phiên bản, những gì thay đổi với ứng dụng của bạn từ Android 12 đến 17, cách thử hành vi gắn với target trước khi nâng targetSdkVersion, và checklist cho mỗi bản phát hành.

Mỗi năm Android ra một bản phát hành lớn, và bản nào cũng thay đổi những hành vi mà ứng dụng của bạn phụ thuộc vào. Test ứng dụng trên các phiên bản Android khác nhau không phải là cài cùng một APK lên sáu chiếc điện thoại rồi xem nó có mở được không, mà là biết thay đổi nào chạm tới bạn ở bản phát hành nào, và vì sao cùng một bản build lại chạy khác nhau trên hai phiên bản.

Bài hướng dẫn này vẽ bản đồ Android 12 đến 17 cho lập trình viên ứng dụng: những gì thay đổi, cách test từng thay đổi bằng adb, và cách thử hành vi gắn với target trước khi bạn nâng targetSdkVersion.

Hai trục, không phải một

Mọi thay đổi hành vi trong Android thuộc về một trong hai nhóm. Thay đổi cho mọi ứng dụng được áp dụng ngay khi thiết bị chạy bản phát hành mới, bất kể ứng dụng của bạn target gì. Thay đổi gắn với target chỉ áp dụng khi targetSdkVersion của bạn tối thiểu bằng API level của bản phát hành đó.

Vậy là bạn có hai trục. Phiên bản thiết bị quyết định nhóm thứ nhất, target của bạn quyết định nhóm thứ hai. Quyền thông báo trên Android 13 cho thấy vì sao cả hai đều quan trọng. Với ứng dụng target API 32 trở xuống, hệ thống tự hiện hộp thoại khi ứng dụng có kênh thông báo và khởi động một activity. Ứng dụng target 33 phải tự xin quyền, vào thời điểm nó chọn. Cùng một đoạn code, hai luồng chạy lần đầu khác nhau.

Vì vậy ma trận là các phiên bản người dùng của bạn đang chạy, nhân với target hiện tại, cộng thêm một cột cho target bạn sắp chuyển lên.

Tổng quan Android 12 đến 17

Phiên bảnAPI levelNhững thay đổi hay làm hỏng ứng dụng nhất
1231 (12L là 32)android:exported tường minh; cờ mutability cho PendingIntent; không khởi động foreground service từ nền; vị trí gần đúng; splash screen của hệ thống
1333quyền POST_NOTIFICATIONS; quyền media chi tiết thay cho quyền đọc bộ nhớ; photo picker; ngôn ngữ riêng cho từng ứng dụng
1434quyền truy cập một phần "Chọn ảnh"; bắt buộc khai báo loại foreground service; exact alarm tắt mặc định với bản cài mới; cờ export cho receiver đăng ký lúc chạy; target dưới 23 không cài được
1535bắt buộc edge-to-edge; thiết bị dùng trang bộ nhớ 16 KB; target dưới 24 không cài được; hiệu ứng predictive back cho ứng dụng đã bật
1636thuộc tính opt-out edge-to-edge bị bỏ qua; predictive back bật mặc định, onBackPressed() không còn được gọi; giới hạn xoay màn hình và đổi kích thước bị bỏ qua trên màn hình lớn
1737Google đã nói cơ chế opt-out tạm thời cho màn hình lớn từ bản 16 sẽ kết thúc ở bản phát hành tiếp theo; hãy đọc toàn bộ danh sách thay đổi hành vi trước khi nâng target

Thông báo (Android 13)

Từ 13 trở đi, thông báo bị tắt cho đến khi người dùng cho phép. Hãy test ba tình huống: cho phép, từ chối, và từ chối hai lần, sau lần đó hệ thống ngừng hiện hộp thoại và ứng dụng phải đưa người dùng tới phần cài đặt. Sau đó test trên 12, nơi không có hộp thoại nào, để chắc rằng phần giới thiệu ban đầu không xin một quyền vốn không tồn tại ở đó.

Chuyển trạng thái cấp quyền giữa các lần thử:

adb shell pm revoke com.example.app android.permission.POST_NOTIFICATIONS
adb shell pm grant com.example.app android.permission.POST_NOTIFICATIONS
adb shell dumpsys package com.example.app | grep POST_NOTIFICATIONS

Thu hồi quyền không đưa hộp thoại lần đầu quay lại sau khi người dùng đã từ chối hai lần. Để thấy luồng mà người dùng mới thấy, hãy gỡ cài đặt rồi cài lại.

Ảnh và media (Android 13 và 14)

Ứng dụng target 33 không còn đọc media bằng READ_EXTERNAL_STORAGE được nữa. Thay vào đó, chúng xin READ_MEDIA_IMAGES, READ_MEDIA_VIDEO hoặc READ_MEDIA_AUDIO. Android 14 thêm lựa chọn thứ ba vào hộp thoại xin quyền ảnh và video: người dùng có thể chỉ chia sẻ những mục họ chọn. Khi đó ứng dụng giữ READ_MEDIA_VISUAL_USER_SELECTED, chỉ thấy những tệp đó, và nên có cách để đổi lựa chọn thay vì giả định mình có cả thư viện ảnh.

Con đường gọn hơn là photo picker, không cần quyền nào cả. ActivityResultContracts.PickVisualMedia mở trình chọn của hệ thống nếu có, nếu không thì dùng ACTION_OPEN_DOCUMENT thay thế. Trên Android 11 và 12, trình chọn đến qua bản cập nhật hệ thống Google Play, nên một chiếc máy cụ thể có thể đi đường này hoặc đường kia. Hãy ghi log isPhotoPickerAvailable() trên từng máy và chắc chắn luồng chạy được theo cả hai cách.

Nạp sẵn thư viện ảnh trước khi test, vì một trình chọn trống che giấu lỗi bố cục:

adb push sample-photos/ /sdcard/Pictures/

Tệp được push vào bộ nhớ dùng chung thường xuất hiện trong MediaStore sau vài giây. Nếu không, hãy mở lại trình chọn.

Chạy nền (Android 12, 14 và 15)

Có ba thay đổi khiến lỗi chạy nền xuất hiện khác nhau giữa các phiên bản. Từ 12, ứng dụng đang chạy nền không còn khởi động foreground service được nữa, trừ một số ít trường hợp ngoại lệ; lệnh gọi ném ra ForegroundServiceStartNotAllowedException. Từ 14, ứng dụng target 34 phải khai báo foregroundServiceType cho mọi foreground service, kèm quyền tương ứng như FOREGROUND_SERVICE_DATA_SYNC, nếu không việc khởi động sẽ thất bại. Từ 15, một foreground service dataSync trong ứng dụng target 35 chỉ được chạy khoảng sáu giờ mỗi ngày, sau đó nhận callback báo hết thời gian.

Exact alarm cũng thay đổi. SCHEDULE_EXACT_ALARM xuất hiện từ 12, và trên 14 nó không còn được cấp mặc định cho ứng dụng mới cài có target từ 13 trở lên. Hãy gọi canScheduleExactAlarms() và xử lý trường hợp false.

Hãy ép điều kiện xảy ra thay vì ngồi chờ. Ba dòng đầu đưa máy vào doze và ứng dụng của bạn vào standby bucket thấp; chạy kịch bản, rồi khôi phục bằng hai dòng cuối:

adb shell dumpsys battery unplug
adb shell dumpsys deviceidle force-idle
adb shell am set-standby-bucket com.example.app rare
adb shell dumpsys deviceidle unforce
adb shell dumpsys battery reset

Edge-to-edge và điều hướng quay lại (Android 15 và 16)

Ứng dụng target 35 vẽ tràn ra sau thanh trạng thái và thanh điều hướng trên Android 15, dù nó có yêu cầu hay không. Thiếu xử lý inset sẽ đẩy toolbar xuống dưới thanh trạng thái, nút bấm xuống dưới thanh cử chỉ và chữ xuống dưới phần khuyết màn hình. Android 15 vẫn chấp nhận thuộc tính opt-out. Trên 16, ứng dụng target 36 mất thuộc tính đó.

Hãy test mọi màn hình ở cả hai chế độ điều hướng, vì điều hướng ba nút để lại một thanh cao hơn cần chừa chỗ. Trên bản build dựa trên AOSP bạn chuyển được bằng adb; ở nơi khác, dùng Cài đặt, Hệ thống, Cử chỉ:

adb shell cmd overlay enable-exclusive --category com.android.internal.systemui.navbar.threebutton
adb shell cmd overlay enable-exclusive --category com.android.internal.systemui.navbar.gestural

Predictive back đi một con đường tương tự. Trên 13 và 14, nó nằm sau một tùy chọn cho nhà phát triển. Trên 15, hiệu ứng hệ thống chạy với ứng dụng đã bật bằng android:enableOnBackInvokedCallback. Trên 16, ứng dụng target 36 được bật sẵn và onBackPressed() không còn được gọi. Hãy tìm trong code base trước khi nâng target:

grep -rn "onBackPressed\|KEYCODE_BACK" app/src/main

Chuyển mọi chỗ tìm được sang OnBackPressedCallback, rồi test vuốt quay lại từ từng màn hình, kể cả dialog và bottom sheet.

Android 16 cũng thay đổi màn hình lớn. Trên màn hình có smallest width từ 600 dp trở lên, ứng dụng target 36 mất khóa xoay màn hình và resizeableActivity="false". Android 16 có một cơ chế opt-out tạm thời, và Google đã nói nó kết thúc ở bản phát hành tiếp theo, nên hãy lên kế hoạch cho việc nó biến mất khi bạn target 37. Nếu ứng dụng của bạn khóa chiều dọc, hãy test nó trên màn hình lớn trước khi nâng target.

Trang bộ nhớ 16 KB (Android 15)

Android 15 bổ sung hỗ trợ cho thiết bị dùng trang bộ nhớ 16 KB thay vì 4 KB. Ứng dụng có native code phải căn chỉnh thư viện cho điều này, và từ tháng 11 năm 2025, Google Play yêu cầu hỗ trợ 16 KB với ứng dụng mới và bản cập nhật target Android 15 trở lên. Kiểm tra kích thước trang của máy và bản build của bạn:

adb shell getconf PAGE_SIZE
zipalign -c -P 16 -v 4 app-release.apk
llvm-objdump -p lib/arm64-v8a/libfoo.so | grep LOAD

Các segment LOAD nên hiện align 2**14. Android Gradle Plugin 8.5.1 trở lên căn chỉnh thư viện không nén bên trong APK, và NDK r28 trở lên mặc định biên dịch căn chỉnh 16 KB, nên thủ phạm thường là thư viện build sẵn của bên thứ ba. Một chiếc máy báo 4096 không cho bạn biết gì về hành vi 16 KB; hãy chạy kiểm tra đó trên system image emulator 16 KB.

Thử thay đổi gắn với target trước khi nâng targetSdk

Bạn không cần nâng targetSdkVersion để thấy phần lớn hành vi gắn với target. Framework tương thích của Android cho phép bật từng thay đổi riêng lẻ cho bản build debuggable:

adb shell dumpsys platform_compat | grep -i edge
adb shell am compat enable CHANGE_NAME com.example.app
adb shell am compat reset CHANGE_NAME com.example.app

Các công tắc tương tự nằm trong Tùy chọn cho nhà phát triển, mục Thay đổi về khả năng tương thích của ứng dụng. Bật từng thay đổi một và chạy lượt smoke test. Khi không còn lỗi nào, nâng target trong một nhánh và chạy toàn bộ ma trận.

Chạy ma trận ở đâu

Phần lớn các đội dùng ba loại thiết bị. Emulator có system image cho mọi API level và không tốn gì, nên hợp với instrumentation test và quét API trong CI. Điện thoại đám mây cho bạn từng bản phát hành trên mẫu điện thoại thật và giữ trạng thái giữa các phiên: Clousd chạy Android 12 đến 17 trên hơn 150 mẫu máy, và máy được đặt lại về trạng thái mới giữa các lần chạy. Điện thoại vật lý vẫn là chuẩn đối chiếu cho camera, cảm biến, đồ họa và hành vi riêng của từng hãng.

Danh sách mẫu máy cho thấy những mẫu nào chạy trên đám mây, và trang kiểm thử ứng dụng chỉ cách nối ma trận vào CI. Mới làm quen với điện thoại từ xa? Hãy bắt đầu với test ứng dụng Android online, và xem bài giải thích về giả lập Android trên cloud để so image emulator với mẫu máy thật.

Checklist cho mỗi bản phát hành

  • Cài bản build hiện tại lên bản phát hành mới với target hiện tại: cài được, khởi động được và sống sót khi tiến trình bị dừng.
  • Đọc trang "behavior changes for all apps" và test mọi mục chạm tới tính năng của bạn.
  • Chạy lần đầu khi chưa cấp quyền nào, rồi lần lượt từ chối từng quyền.
  • Thông báo: thời điểm hiện hộp thoại, từ chối, và đường dẫn tới cài đặt.
  • Media: photo picker, quyền truy cập một phần, thư viện ảnh trống.
  • Chạy nền: foreground service, exact alarm, doze và standby bucket.
  • Bố cục: inset ở cả hai chế độ điều hướng, phần khuyết màn hình, cỡ chữ 1.3, chế độ tối.
  • Quay lại: vuốt quay lại từ mọi màn hình, dialog và bottom sheet.
  • Native code: căn chỉnh 16 KB cho mọi thư viện.
  • Nâng target trong một nhánh, đọc trang "behavior changes for apps targeting" level mới, rồi lặp lại.

Sẵn sàng khởi chạy
chiếc điện thoại đám mây đầu tiên?

Dùng thử miễn phí 30 phút

Không cần thẻ