Các thay đổi về hành vi của Android 8.0

Cùng với các tính năng và chức năng mới, Android 8.0 (API cấp 26) còn có nhiều thay đổi về hành vi của hệ thống và API. Tài liệu này nêu bật một số thay đổi chính mà bạn nên hiểu và tính đến trong ứng dụng của mình.

Hầu hết các thay đổi này ảnh hưởng đến tất cả ứng dụng, bất kể ứng dụng nhắm đến phiên bản Android nào. Tuy nhiên, một số thay đổi chỉ ảnh hưởng đến những ứng dụng nhắm đến Android 8.0. Để đảm bảo tính rõ ràng, trang này được chia thành hai phần: Thay đổi đối với tất cả ứng dụngThay đổi đối với ứng dụng nhắm đến Android 8.0.

Thay đổi đối với tất cả ứng dụng

Những thay đổi về hành vi này áp dụng cho tất cả ứng dụng khi chạy trên nền tảng Android 8.0 (API cấp 26), bất kể cấp độ API mà ứng dụng nhắm đến. Tất cả nhà phát triển đều nên xem xét những thay đổi này và sửa đổi ứng dụng của mình để hỗ trợ chúng cho phù hợp (nếu ứng dụng có áp dụng).

Giới hạn thực thi trong nền

Là một trong những thay đổi mà Android 8.0 (API cấp 26) giới thiệu để cải thiện thời lượng pin, khi ứng dụng của bạn chuyển sang trạng thái đã lưu vào bộ nhớ đệm mà không có thành phần nào đang hoạt động, hệ thống sẽ giải phóng mọi khoá chế độ thức mà ứng dụng giữ.

Ngoài ra, để cải thiện hiệu suất của thiết bị, hệ thống sẽ giới hạn một số hành vi nhất định của các ứng dụng không chạy ở nền trước. Cụ thể:

  • Các ứng dụng đang chạy ở chế độ nền hiện có giới hạn về mức độ tự do truy cập vào các dịch vụ nền.
  • Ứng dụng không thể sử dụng tệp kê khai để đăng ký hầu hết các thông báo truyền tin ngầm (tức là thông báo truyền tin không nhắm đến ứng dụng cụ thể).

Theo mặc định, các quy định hạn chế này chỉ áp dụng cho những ứng dụng nhắm đến O. Tuy nhiên, người dùng có thể bật các hạn chế này cho bất kỳ ứng dụng nào trên màn hình Cài đặt, ngay cả khi ứng dụng đó không nhắm đến O.

Android 8.0 (API cấp 26) cũng bao gồm các thay đổi sau đây đối với các phương thức cụ thể:

  • Phương thức startService() hiện sẽ gửi một IllegalStateException nếu một ứng dụng nhắm đến Android 8.0 cố gắng sử dụng phương thức đó trong trường hợp không được phép tạo dịch vụ nền.
  • Phương thức Context.startForegroundService() mới sẽ bắt đầu một dịch vụ trên nền trước. Hệ thống cho phép ứng dụng gọi Context.startForegroundService() ngay cả khi ứng dụng đang chạy ở chế độ nền. Tuy nhiên, ứng dụng phải gọi phương thức startForeground() của dịch vụ đó trong vòng 5 giây sau khi tạo dịch vụ.

Để biết thêm thông tin, hãy xem phần Giới hạn về hoạt động thực thi ở chế độ nền.

Giới hạn quyền truy cập thông tin vị trí ở chế độ nền trên Android

Để duy trì pin, trải nghiệm người dùng và tình trạng hệ thống, các ứng dụng chạy nền sẽ nhận được thông tin cập nhật vị trí ít thường xuyên hơn khi được sử dụng trên thiết bị chạy Android 8.0. Thay đổi về hành vi này ảnh hưởng đến tất cả ứng dụng nhận thông tin cập nhật vị trí, bao gồm cả Dịch vụ Google Play.

Những thay đổi này ảnh hưởng đến các API sau:

  • Trình cung cấp vị trí kết hợp (FLP)
  • Khoanh vùng địa lý
  • Đo lường GNSS
  • Trình quản lý vị trí
  • Trình quản lý Wi-Fi

Để đảm bảo ứng dụng của bạn chạy như mong đợi, hãy hoàn tất các bước sau:

  • Xem lại logic của ứng dụng và đảm bảo rằng bạn đang sử dụng các API vị trí mới nhất.
  • Kiểm thử để đảm bảo ứng dụng của bạn thể hiện hành vi mà bạn mong đợi cho từng trường hợp sử dụng.
  • Cân nhắc sử dụng Trình cung cấp vị trí kết hợp (FLP) hoặc tính năng khoanh vùng địa lý để xử lý các trường hợp sử dụng phụ thuộc vào vị trí hiện tại của người dùng.

Để biết thêm thông tin về những thay đổi này, hãy xem phần Giới hạn về thông tin vị trí ở chế độ nền.

Lối tắt ứng dụng

Android 8.0 (API cấp 26) có các thay đổi sau đối với lối tắt ứng dụng:

  • Thông báo truyền tin com.android.launcher.action.INSTALL_SHORTCUT không còn ảnh hưởng đến ứng dụng của bạn nữa vì hiện là thông báo truyền tin ngầm ẩn, riêng tư. Thay vào đó, bạn nên tạo lối tắt ứng dụng bằng cách sử dụng phương thức requestPinShortcut() từ lớp ShortcutManager.
  • Ý định ACTION_CREATE_SHORTCUT hiện có thể tạo lối tắt ứng dụng mà bạn quản lý bằng lớp ShortcutManager. Ý định này cũng có thể tạo các lối tắt trình chạy cũ không tương tác với ShortcutManager. Trước đây, ý định này chỉ có thể tạo lối tắt trình chạy cũ.
  • Lối tắt được tạo bằng requestPinShortcut() và lối tắt được tạo trong hoạt động xử lý ý định ACTION_CREATE_SHORTCUT nay là lối tắt ứng dụng chính thức. Do đó, các ứng dụng hiện có thể cập nhật các thông tin đó bằng các phương thức trong ShortcutManager.
  • Các lối tắt cũ vẫn giữ nguyên chức năng của các phiên bản Android trước, nhưng bạn phải chuyển đổi các lối tắt đó thành lối tắt ứng dụng theo cách thủ công trong ứng dụng.

Để tìm hiểu thêm về các thay đổi đối với lối tắt ứng dụng, hãy xem hướng dẫn về tính năng Ghim lối tắt và tiện ích.

Ngôn ngữ và quốc tế hoá

Android 7.0 (API cấp 24) đã giới thiệu khái niệm về khả năng chỉ định Ngôn ngữ danh mục mặc định, nhưng một số API tiếp tục sử dụng phương thức Locale.getDefault() chung mà không có đối số, trong khi đáng lẽ phải sử dụng Ngôn ngữ danh mục DISPLAY mặc định. Trong Android 8.0 (API cấp 26), các phương thức sau đây hiện sử dụng Locale.getDefault(Category.DISPLAY) thay vì Locale.getDefault():

Locale.getDisplayScript(Locale) cũng quay lại Locale.getDefault() khi không có giá trị displayScript được chỉ định cho đối số Locale.

Sau đây là các thay đổi khác liên quan đến ngôn ngữ và quốc tế hoá:

  • Việc gọi Currency.getDisplayName(null) sẽ gửi một NullPointerException, khớp với hành vi được ghi nhận.
  • Tính năng phân tích cú pháp tên múi giờ đã thay đổi. Trước đây, các thiết bị Android sử dụng giá trị đồng hồ hệ thống được lấy mẫu tại thời điểm khởi động để lưu tên múi giờ vào bộ nhớ đệm dùng để phân tích cú pháp ngày và giờ. Do đó, quá trình phân tích cú pháp có thể bị ảnh hưởng tiêu cực nếu đồng hồ hệ thống không chính xác tại thời điểm khởi động hoặc trong các trường hợp hiếm hơn khác.

    Giờ đây, trong các trường hợp phổ biến, logic phân tích cú pháp sử dụng ICU và giá trị đồng hồ hệ thống hiện tại khi phân tích cú pháp tên múi giờ. Thay đổi này cung cấp kết quả chính xác hơn, có thể khác với các phiên bản Android trước đó khi ứng dụng của bạn sử dụng các lớp như SimpleDateFormat.

  • Android 8.0 (API cấp 26) cập nhật phiên bản ICU lên phiên bản 58.

Cửa sổ cảnh báo

Nếu một ứng dụng sử dụng quyền SYSTEM_ALERT_WINDOW và sử dụng một trong các loại cửa sổ sau đây để cố gắng hiển thị cửa sổ cảnh báo phía trên các ứng dụng và cửa sổ hệ thống khác:

...thì các cửa sổ này sẽ luôn xuất hiện bên dưới các cửa sổ sử dụng loại cửa sổ TYPE_APPLICATION_OVERLAY. Nếu nhắm đến Android 8.0 (API cấp 26), ứng dụng sẽ sử dụng loại cửa sổ TYPE_APPLICATION_OVERLAY để hiển thị cửa sổ cảnh báo.

Để biết thêm thông tin, hãy xem phần Các loại cửa sổ phổ biến cho cửa sổ cảnh báo trong phần thay đổi về hành vi đối với Ứng dụng nhắm đến Android 8.0.

Nhập và điều hướng

Với sự ra đời của các ứng dụng Android trên ChromeOS và các kiểu dáng lớn khác, chẳng hạn như máy tính bảng, chúng tôi nhận thấy việc sử dụng tính năng điều hướng bằng bàn phím trong các ứng dụng Android đang hồi sinh. Trong Android 8.0 (API cấp 26), chúng tôi đã tái xử lý bằng cách sử dụng bàn phím làm thiết bị đầu vào điều hướng, dẫn đến một mô hình đáng tin cậy, dễ dự đoán hơn cho hoạt động điều hướng dựa trên mũi tên và thẻ.

Cụ thể, chúng tôi đã thực hiện những thay đổi sau đây đối với hành vi của phần tử trong tiêu điểm:

  • Nếu bạn chưa xác định màu trạng thái tiêu điểm nào cho đối tượng View (nền trước hoặc nền có thể vẽ), thì khung này sẽ đặt màu làm nổi bật tiêu điểm mặc định cho View. Điểm nổi bật của tiêu điểm này là một gợn sóng có thể vẽ dựa trên giao diện của hoạt động.

    Nếu bạn không muốn một đối tượng View sử dụng điểm đánh dấu mặc định này khi nhận được tiêu điểm, hãy đặt thuộc tính android:defaultFocusHighlightEnabled thành false trong tệp XML bố cục chứa View hoặc truyền false vào setDefaultFocusHighlightEnabled() trong logic giao diện người dùng của ứng dụng.

  • Để kiểm tra mức độ ảnh hưởng của phương thức nhập bằng bàn phím đối với tiêu điểm của thành phần trên giao diện người dùng, bạn có thể bật tuỳ chọn dành cho nhà phát triển Drawing > Show layout bounds (Vẽ > Hiển thị giới hạn bố cục). Trong Android 8.0, tuỳ chọn này sẽ hiển thị biểu tượng "X" trên phần tử hiện có tiêu điểm.

Ngoài ra, tất cả các thành phần trên thanh công cụ trong Android 8.0 đều tự động là các cụm điều hướng bằng bàn phím, giúp người dùng dễ dàng điều hướng vào và ra khỏi từng thanh công cụ.

Để tìm hiểu thêm về cách cải thiện khả năng hỗ trợ thao tác bằng bàn phím trong ứng dụng, hãy đọc hướng dẫn Hỗ trợ thao tác bằng bàn phím.

Tự động điền biểu mẫu trên web

Giờ đây, Khung tự động điền của Android tích hợp sẵn tính năng hỗ trợ cho chức năng tự động điền, các phương thức sau đây liên quan đến đối tượng WebView đã thay đổi đối với các ứng dụng được cài đặt trên thiết bị chạy Android 8.0 (API cấp 26):

WebSettings
  • Phương thức getSaveFormData() hiện trả về false. Trước đây, phương thức này trả về true.
  • Việc gọi setSaveFormData() không có hiệu lực nữa.
WebViewDatabase
  • Việc gọi clearFormData() không còn có hiệu lực nữa.
  • Phương thức hasFormData() hiện trả về false. Trước đây, phương thức này trả về true khi biểu mẫu chứa dữ liệu.

Hỗ trợ tiếp cận

Android 8.0 (API cấp 26) có các thay đổi sau đây đối với chức năng hỗ trợ tiếp cận:

  • Khung hỗ trợ tiếp cận hiện chuyển đổi tất cả cử chỉ nhấn đúp thành thao tác ACTION_CLICK. Thay đổi này cho phép TalkBack hoạt động giống như các dịch vụ hỗ trợ tiếp cận khác.

    Nếu các đối tượng View của ứng dụng sử dụng tính năng xử lý thao tác chạm tuỳ chỉnh, thì bạn nên xác minh rằng các đối tượng đó vẫn hoạt động với TalkBack. Bạn có thể chỉ cần đăng ký trình xử lý lượt nhấp mà các đối tượng View sử dụng. Nếu TalkBack vẫn không nhận ra các cử chỉ được thực hiện trên các đối tượng View này, hãy ghi đè performAccessibilityAction().

  • Các dịch vụ hỗ trợ tiếp cận hiện đã nhận biết được tất cả các thực thể ClickableSpan trong đối tượng TextView của ứng dụng.

Để tìm hiểu thêm về cách giúp ứng dụng dễ tiếp cận hơn, hãy xem phần Hỗ trợ tiếp cận.

Kết nối mạng và HTTP(S)

Android 8.0 (API cấp 26) bao gồm các thay đổi về hành vi sau đây đối với kết nối mạng và HTTP(S):

  • Các yêu cầu OPTIONS không có nội dung sẽ có tiêu đề Content-Length: 0. Trước đây, các tệp này không có tiêu đề Content-Length.
  • HttpURLConnection chuẩn hoá các URL chứa đường dẫn trống bằng cách thêm dấu gạch chéo sau tên máy chủ hoặc tên cơ quan có dấu gạch chéo. Ví dụ: hàm này chuyển đổi http://example.com thành http://example.com/.
  • Bộ chọn proxy tuỳ chỉnh được đặt thông qua ProxySelector.setDefault() chỉ nhắm đến địa chỉ (lược đồ, máy chủ và cổng) của một URL được yêu cầu. Do đó, lựa chọn proxy chỉ có thể dựa trên các giá trị đó. URL được chuyển đến bộ chọn proxy tuỳ chỉnh không bao gồm đường dẫn, tham số truy vấn hoặc mảnh của URL được yêu cầu.
  • URI không được chứa nhãn trống.

    Trước đây, nền tảng này hỗ trợ một giải pháp để chấp nhận các nhãn trống trong tên máy chủ lưu trữ. Đây là một cách sử dụng URI bất hợp pháp. Giải pháp này là để tương thích với các bản phát hành libcore cũ. Các nhà phát triển sử dụng API không chính xác sẽ thấy thông báo ADB: "URI example..com có nhãn trống trong tên máy chủ. Định dạng này không đúng định dạng và sẽ không được chấp nhận trong các bản phát hành Android trong tương lai." Android 8.0 loại bỏ giải pháp này; hệ thống trả về giá trị rỗng cho các URI không đúng định dạng.

  • Quá trình triển khai HttpsURLConnection của Android 8.0 không thực hiện dự phòng phiên bản giao thức TLS/SSL không an toàn.
  • Cách xử lý các kết nối HTTP(S) tạo đường hầm đã thay đổi như sau:
    • Khi tạo đường hầm cho kết nối HTTPS qua kết nối, hệ thống sẽ đặt chính xác số cổng (:443) vào dòng Máy chủ lưu trữ khi gửi thông tin này đến máy chủ trung gian. Trước đây, số cổng chỉ xuất hiện trong dòng CONNECT.
    • Hệ thống không còn gửi tiêu đề tác nhân người dùng và uỷ quyền proxy từ yêu cầu được tạo đường hầm đến máy chủ proxy nữa.

      Hệ thống không còn gửi tiêu đề uỷ quyền proxy trên Http(s)URLConnection được tạo đường hầm đến proxy khi thiết lập đường hầm. Thay vào đó, hệ thống sẽ tạo một tiêu đề uỷ quyền proxy rồi gửi tiêu đề này đến proxy khi proxy đó gửi HTTP 407 để phản hồi yêu cầu ban đầu.

      Tương tự, hệ thống không còn sao chép tiêu đề tác nhân người dùng từ yêu cầu được tạo đường hầm sang yêu cầu proxy thiết lập đường hầm. Thay vào đó, thư viện sẽ tạo một tiêu đề tác nhân người dùng cho yêu cầu đó.

  • Phương thức send(java.net.DatagramPacket) sẽ gửi một SocketException nếu phương thức connect() đã thực thi trước đó không thành công.
    • DatagramSocket.connect() đặt pendingSocketException nếu có lỗi nội bộ. Trước Android 8.0, lệnh gọi recv() tiếp theo gửi một SocketException mặc dù lệnh gọi send() đã thành công. Để đảm bảo tính nhất quán, cả hai lệnh gọi hiện đều gửi một SocketException.
  • InetAddress.isReachable() thử ICMP trước khi quay lại giao thức TCP Echo.
    • Một số máy chủ chặn cổng 7 (TCP Echo), chẳng hạn như google.com, hiện có thể truy cập được nếu chấp nhận giao thức ICMP Echo.
    • Đối với các máy chủ thực sự không truy cập được, thay đổi này đồng nghĩa với việc sẽ mất gấp đôi lượng thời gian trước khi lệnh gọi được trả về.

Bluetooth

Android 8.0 (API cấp 26) thực hiện những thay đổi sau đây đối với độ dài của dữ liệu mà phương thức ScanRecord.getBytes() truy xuất:

  • Phương thức getBytes() không đưa ra giả định nào về số byte nhận được. Do đó, ứng dụng không được dựa vào bất kỳ số lượng byte tối thiểu hoặc tối đa nào được trả về. Thay vào đó, các hàm này nên đánh giá chiều dài của mảng kết quả.
  • Các thiết bị tương thích với Bluetooth 5 có thể trả về độ dài dữ liệu vượt quá mức tối đa trước đó là khoảng 60 byte.
  • Nếu thiết bị từ xa không cung cấp phản hồi quét, thì hệ thống cũng có thể trả về ít hơn 60 byte.

Khả năng kết nối liền mạch

Android 8.0 (API cấp 26) cải tiến một số tính năng trong phần Cài đặt Wi-Fi để giúp người dùng dễ dàng chọn mạng Wi-Fi mang lại trải nghiệm tốt nhất. Sau đây là một số thay đổi cụ thể:

  • Cải thiện độ ổn định và độ tin cậy.
  • Giao diện người dùng dễ đọc hơn.
  • Một trình đơn Lựa chọn ưu tiên về Wi-Fi hợp nhất.
  • Trên các thiết bị tương thích, Wi-Fi sẽ tự động kích hoạt khi có mạng đã lưu chất lượng cao ở gần.

Bảo mật

Android 8.0 có các thay đổi sau liên quan đến tính bảo mật:

  • Nền tảng này không còn hỗ trợ SSLv3.
  • Khi thiết lập kết nối HTTPS với một máy chủ triển khai không chính xác tính năng đàm phán phiên bản giao thức TLS, HttpsURLConnection sẽ không còn thử giải pháp quay lại các phiên bản giao thức TLS trước đó và thử lại.
  • Android 8.0 (API cấp 26) áp dụng bộ lọc điện toán bảo mật (SECCOMP) cho tất cả ứng dụng. Danh sách các lệnh gọi hệ thống được phép chỉ dành cho những lệnh gọi được hiển thị thông qua bionic. Mặc dù có một số lệnh gọi hệ thống khác được cung cấp để đảm bảo khả năng tương thích ngược, nhưng bạn không nên sử dụng những lệnh gọi này.
  • Các đối tượng WebView của ứng dụng hiện chạy ở chế độ đa xử lý. Nội dung web được xử lý trong một quy trình riêng biệt, tách biệt với quy trình của ứng dụng để tăng cường bảo mật.
  • Bạn không còn có thể giả định rằng tệp APK nằm trong các thư mục có tên kết thúc bằng -1 hoặc -2. Các ứng dụng nên dùng sourceDir để lấy thư mục này và không trực tiếp dựa vào định dạng thư mục này.
  • Để biết thông tin về các tính năng bảo mật nâng cao liên quan đến việc sử dụng thư viện gốc, hãy xem phần Thư viện gốc.

Ngoài ra, Android 8.0 (API cấp 26) ra mắt các thay đổi sau đây liên quan đến việc cài đặt ứng dụng không xác định không rõ nguồn gốc:

  • Giá trị của chế độ cài đặt cũ INSTALL_NON_MARKET_APPS hiện luôn là 1. Để xác định xem một nguồn không xác định có thể cài đặt ứng dụng bằng trình cài đặt gói hay không, bạn nên sử dụng giá trị trả về của canRequestPackageInstalls().
  • Nếu bạn cố gắng thay đổi giá trị của INSTALL_NON_MARKET_APPS bằng setSecureSetting(), thì một UnsupportedOperationException sẽ được gửi. Để ngăn người dùng cài đặt ứng dụng không xác định bằng các nguồn không xác định, bạn nên áp dụng chế độ hạn chế người dùng DISALLOW_INSTALL_UNKNOWN_SOURCES.
  • Hồ sơ được quản lý được tạo trên các thiết bị chạy Android 8.0 (API cấp 26) sẽ tự động bật chế độ hạn chế người dùng DISALLOW_INSTALL_UNKNOWN_SOURCES. Đối với các hồ sơ được quản lý hiện có trên các thiết bị được nâng cấp lên Android 8.0, quy tắc hạn chế người dùng DISALLOW_INSTALL_UNKNOWN_SOURCES sẽ tự động bật, trừ phi chủ sở hữu hồ sơ đã tắt rõ ràng quy tắc hạn chế này (trước khi nâng cấp) bằng cách đặt INSTALL_NON_MARKET_APPS thành 1.

Để biết thêm thông tin chi tiết về cách cài đặt ứng dụng không xác định, hãy xem hướng dẫn về Quyền cài đặt ứng dụng không xác định.

Để biết thêm nguyên tắc về cách giúp ứng dụng của bạn an toàn hơn, hãy xem bài viết Bảo mật dành cho nhà phát triển Android.

Quyền riêng tư

Android 8.0 (API cấp 26) thực hiện các thay đổi sau đây liên quan đến quyền riêng tư đối với nền tảng.

  • Giờ đây, nền tảng này xử lý các giá trị nhận dạng theo cách khác.
    • Đối với các ứng dụng được cài đặt trước phiên bản Android 8.0 (API cấp 26) (API cấp 26) trước khi cài đặt qua OTA, giá trị của ANDROID_ID vẫn giữ nguyên trừ phi bị gỡ cài đặt rồi cài đặt lại sau OTA. Để giữ nguyên các giá trị trong quá trình gỡ cài đặt sau khi cập nhật qua mạng, nhà phát triển có thể liên kết các giá trị cũ và mới bằng cách sử dụng tính năng Sao lưu khoá/giá trị.
    • Đối với các ứng dụng được cài đặt trên một thiết bị chạy Android 8.0, giá trị của ANDROID_ID hiện được giới hạn theo khoá ký ứng dụng, cũng như theo người dùng. Giá trị của ANDROID_ID là duy nhất cho mỗi tổ hợp khoá ký ứng dụng, người dùng và thiết bị. Do đó, các ứng dụng có khoá ký khác nhau chạy trên cùng một thiết bị sẽ không còn thấy cùng một mã nhận dạng Android (ngay cả đối với cùng một người dùng).
    • Giá trị của ANDROID_ID không thay đổi khi gỡ cài đặt hoặc cài đặt lại gói, miễn là khoá ký vẫn giống nhau (và ứng dụng chưa được cài đặt trước khi cập nhật qua mạng cho phiên bản Android 8.0).
    • Giá trị của ANDROID_ID không thay đổi ngay cả khi bản cập nhật hệ thống làm khoá ký gói thay đổi.
    • Trên các thiết bị vận chuyển bằng Dịch vụ Google Play và Mã nhận dạng cho quảng cáo, bạn phải sử dụng Mã nhận dạng cho quảng cáo. Một hệ thống đơn giản, chuẩn để kiếm tiền từ ứng dụng, Mã nhận dạng cho quảng cáo là một mã nhận dạng riêng biệt mà người dùng có thể đặt lại cho quảng cáo. Ứng dụng này do Dịch vụ Google Play cung cấp.

      Các nhà sản xuất thiết bị khác nên tiếp tục cung cấp ANDROID_ID.

  • Việc truy vấn thuộc tính hệ thống net.hostname sẽ trả về kết quả rỗng.

Ghi nhật ký các ngoại lệ chưa nắm bắt được

Nếu một ứng dụng cài đặt Thread.UncaughtExceptionHandler không gọi đến Thread.UncaughtExceptionHandler mặc định, thì hệ thống sẽ không tắt ứng dụng khi xảy ra ngoại lệ chưa được phát hiện. Kể từ Android 8.0 (API cấp 26), hệ thống sẽ ghi lại dấu vết ngăn xếp ngoại lệ trong trường hợp này; trong các phiên bản nền tảng trước đó, hệ thống sẽ không ghi lại dấu vết ngăn xếp ngoại lệ.

Bạn nên luôn gọi các quá trình triển khai Thread.UncaughtExceptionHandler tuỳ chỉnh đến trình xử lý mặc định. Những ứng dụng tuân theo đề xuất này sẽ không bị ảnh hưởng bởi sự thay đổi trong Android 8.0.

Thay đổi chữ ký findViewById()

Tất cả các thực thể của phương thức findViewById() hiện trả về <T extends View> T thay vì View. Thay đổi này có những tác động sau:

  • Điều này có thể khiến mã hiện có có loại dữ liệu trả về không rõ ràng, ví dụ: nếu có cả someMethod(View)someMethod(TextView) lấy kết quả của lệnh gọi đến findViewById().
  • Khi sử dụng ngôn ngữ nguồn Java 8, bạn cần truyền rõ ràng sang View khi loại dữ liệu trả về không bị ràng buộc (ví dụ: assertNotNull(findViewById(...)).someViewMethod()).
  • Các phương thức ghi đè findViewById() không phải cuối cùng (ví dụ: Activity.findViewById()) sẽ cần cập nhật loại dữ liệu trả về.

Thay đổi số liệu thống kê sử dụng của trình cung cấp danh bạ

Trong các phiên bản Android trước đây, thành phần Trình cung cấp danh bạ cho phép nhà phát triển lấy dữ liệu sử dụng cho từng người liên hệ. Dữ liệu sử dụng này cho biết thông tin về từng địa chỉ email và từng số điện thoại liên kết với một người liên hệ, bao gồm số lần liên hệ với người liên hệ đó và lần liên hệ gần đây nhất với người liên hệ đó. Các ứng dụng yêu cầu quyền READ_CONTACTS có thể đọc dữ liệu này.

Ứng dụng vẫn có thể đọc dữ liệu này nếu yêu cầu quyền READ_CONTACTS. Trong Android 8.0 (API cấp 26) trở lên, các truy vấn cho dữ liệu sử dụng sẽ trả về giá trị gần đúng thay vì giá trị chính xác. Hệ thống Android duy trì các giá trị chính xác trong nội bộ, vì vậy, thay đổi này không ảnh hưởng đến API tự động hoàn thành.

Thay đổi này về hành vi ảnh hưởng đến các tham số truy vấn sau:

Xử lý bộ sưu tập

AbstractCollection.removeAll()AbstractCollection.retainAll() hiện luôn gửi một NullPointerException; trước đây, NullPointerException không được gửi khi bộ sưu tập trống. Thay đổi này giúp hành vi nhất quán với tài liệu.

Android Enterprise

Android 8.0 (API cấp 26) thay đổi hành vi của một số API và tính năng cho ứng dụng doanh nghiệp, bao gồm cả trình điều khiển chính sách thiết bị (DPC). Những thay đổi này bao gồm:

  • Các hành vi mới giúp ứng dụng hỗ trợ hồ sơ công việc trên thiết bị được quản lý hoàn toàn.
  • Các thay đổi đối với quá trình xử lý bản cập nhật hệ thống, xác minh ứng dụng và xác thực để tăng tính toàn vẹn của thiết bị và hệ thống.
  • Những cải tiến đối với trải nghiệm người dùng đối với việc cấp phép, thông báo, màn hình Gần đây và VPN luôn bật.

Để xem tất cả các thay đổi dành cho doanh nghiệp trong Android 8.0 (API cấp 26) và tìm hiểu cách các thay đổi đó có thể ảnh hưởng đến ứng dụng của bạn, hãy đọc bài viết Android trong doanh nghiệp.

Ứng dụng nhắm đến Android 8.0

Những thay đổi về hành vi này chỉ áp dụng cho các ứng dụng nhắm đến Android 8.0 (API cấp 26) trở lên. Các ứng dụng biên dịch cho Android 8.0 hoặc đặt targetSdkVersion thành Android 8.0 trở lên phải sửa đổi ứng dụng của mình để hỗ trợ các hành vi này cho phù hợp (nếu ứng dụng có hỗ trợ).

Cửa sổ cảnh báo

Các ứng dụng dùng quyền SYSTEM_ALERT_WINDOW không thể dùng các loại cửa sổ sau để hiện cửa sổ thông báo phía trên các ứng dụng và cửa sổ hệ thống khác nữa:

Thay vào đó, ứng dụng phải sử dụng một loại cửa sổ mới có tên là TYPE_APPLICATION_OVERLAY.

Khi sử dụng loại cửa sổ TYPE_APPLICATION_OVERLAY để hiện cửa sổ cảnh báo cho ứng dụng, hãy lưu ý các đặc điểm sau của loại cửa sổ mới:

  • Cửa sổ cảnh báo của ứng dụng luôn xuất hiện trong các cửa sổ hệ thống quan trọng, chẳng hạn như thanh trạng thái và IME.
  • Hệ thống có thể di chuyển hoặc đổi kích thước các cửa sổ sử dụng loại cửa sổ TYPE_APPLICATION_OVERLAY để cải thiện khả năng hiển thị màn hình.
  • Bằng cách mở ngăn thông báo, người dùng có thể truy cập vào phần cài đặt để chặn một ứng dụng hiển thị các cửa sổ cảnh báo hiển thị bằng loại cửa sổ TYPE_APPLICATION_OVERLAY.

Thông báo về nội dung thay đổi

Android 8.0 (API cấp 26) thay đổi cách hoạt động của ContentResolver.notifyChange()registerContentObserver(Uri, boolean, ContentObserver) đối với các ứng dụng nhắm đến Android 8.0.

Các API này hiện yêu cầu phải xác định một ContentProvider hợp lệ cho cơ quan quản lý trong tất cả Uri. Việc xác định ContentProvider hợp lệ với các quyền liên quan sẽ giúp bảo vệ ứng dụng của bạn khỏi các thay đổi về nội dung từ ứng dụng độc hại, đồng thời ngăn bạn làm rò rỉ dữ liệu riêng tư có thể cho các ứng dụng độc hại.

Tiêu điểm của thành phần hiển thị

Các đối tượng View có thể nhấp vào hiện cũng có thể lấy nét theo mặc định. Nếu bạn muốn đối tượng View có thể nhấp nhưng không thể lấy tiêu điểm, hãy đặt thuộc tính android:focusable thành false trong tệp XML bố cục chứa View hoặc truyền false vào setFocusable() trong logic giao diện người dùng của ứng dụng.

So khớp tác nhân người dùng trong tính năng phát hiện trình duyệt

Android 8.0 (API cấp 26) trở lên có chuỗi giá trị nhận dạng bản dựng OPR. Một số kết quả khớp mẫu có thể khiến logic phát hiện trình duyệt xác định nhầm một trình duyệt không phải Opera là Opera. Ví dụ về kiểu so khớp mẫu như vậy có thể là:

if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}

Để tránh các vấn đề phát sinh từ việc xác định sai như vậy, hãy sử dụng một chuỗi khác với OPR làm kiểu khớp mẫu cho trình duyệt Opera.

Bảo mật

Các thay đổi sau đây ảnh hưởng đến tính bảo mật trong Android 8.0 (API cấp 26):

  • Nếu cấu hình bảo mật mạng của ứng dụng chọn không hỗ trợ lưu lượng truy cập văn bản thô, thì các đối tượng WebView của ứng dụng sẽ không thể truy cập vào trang web qua HTTP. Thay vào đó, mỗi đối tượng WebView phải sử dụng HTTPS.
  • Chế độ cài đặt hệ thống Cho phép nguồn không xác định đã bị xoá; thay vào đó, quyền Cài đặt ứng dụng không xác định sẽ quản lý các lượt cài đặt ứng dụng không xác định từ các nguồn không xác định. Để tìm hiểu thêm về quyền mới này, hãy xem hướng dẫn về Quyền cài đặt ứng dụng không xác định.

Để biết thêm nguyên tắc về cách giúp ứng dụng của bạn an toàn hơn, hãy xem bài viết Bảo mật dành cho nhà phát triển Android.

Quyền truy cập vào tài khoản và khả năng phát hiện tài khoản

Trong Android 8.0 (API cấp 26), các ứng dụng không thể truy cập vào tài khoản người dùng nữa, trừ phi trình xác thực sở hữu các tài khoản đó hoặc người dùng cấp quyền truy cập đó. Quyền GET_ACCOUNTS không còn đủ nữa. Để được cấp quyền truy cập vào một tài khoản, ứng dụng phải sử dụng AccountManager.newChooseAccountIntent() hoặc một phương thức dành riêng cho trình xác thực. Sau khi có quyền truy cập vào các tài khoản, ứng dụng có thể gọi AccountManager.getAccounts() để truy cập vào các tài khoản đó.

Android 8.0 không dùng LOGIN_ACCOUNTS_CHANGED_ACTION nữa. Thay vào đó, ứng dụng nên sử dụng addOnAccountsUpdatedListener() để nhận thông tin cập nhật về tài khoản trong thời gian chạy.

Để biết thông tin về các API và phương thức mới được thêm vào để truy cập vào tài khoản và khả năng khám phá, hãy xem phần Truy cập vào tài khoản và khả năng khám phá trong phần API mới của tài liệu này.

Quyền riêng tư

Các thay đổi sau đây ảnh hưởng đến quyền riêng tư trong Android 8.0 (API cấp 26).

  • Các thuộc tính hệ thống net.dns1, net.dns2, net.dns3net.dns4 không còn được cung cấp nữa. Đây là thay đổi giúp cải thiện quyền riêng tư trên nền tảng.
  • Để lấy thông tin về mạng, chẳng hạn như máy chủ DNS, các ứng dụng có quyền ACCESS_NETWORK_STATE có thể đăng ký đối tượng NetworkRequest hoặc NetworkCallback. Các lớp này có trong Android 5.0 (API cấp 21) trở lên.
  • Ngừng sử dụng Build.SERIAL. Thay vào đó, các ứng dụng cần biết số sê-ri phần cứng nên sử dụng phương thức Build.getSerial() mới. Phương thức này yêu cầu quyền READ_PHONE_STATE.
  • API LauncherApps không còn cho phép các ứng dụng trong hồ sơ công việc nhận thông tin về hồ sơ chính. Khi người dùng ở trong một hồ sơ công việc, API LauncherApps sẽ hoạt động như thể không có ứng dụng nào được cài đặt trong các hồ sơ khác trong cùng một nhóm hồ sơ. Giống như trước đây, các nỗ lực truy cập vào các hồ sơ không liên quan sẽ gây ra SecurityExceptions.

Quyền

Trước Android 8.0 (API cấp 26), nếu một ứng dụng yêu cầu quyền trong thời gian chạy và quyền đó được cấp, thì hệ thống cũng cấp nhầm cho ứng dụng các quyền còn lại thuộc cùng một nhóm quyền và đã được đăng ký trong tệp kê khai.

Đối với các ứng dụng nhắm đến Android 8.0, hành vi này đã được khắc phục. Ứng dụng chỉ được cấp những quyền mà ứng dụng đã yêu cầu một cách rõ ràng. Tuy nhiên, sau khi người dùng cấp quyền cho ứng dụng, tất cả các yêu cầu cấp quyền tiếp theo trong nhóm quyền đó sẽ tự động được cấp.

Ví dụ: giả sử một ứng dụng liệt kê cả READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE trong tệp kê khai. Ứng dụng yêu cầu READ_EXTERNAL_STORAGE và người dùng cấp quyền đó. Nếu ứng dụng nhắm đến API cấp 25 trở xuống, thì hệ thống cũng cấp WRITE_EXTERNAL_STORAGE cùng lúc vì quyền này thuộc cùng một nhóm quyền STORAGE và cũng được đăng ký trong tệp kê khai. Nếu ứng dụng nhắm đến Android 8.0 (API cấp 26), thì hệ thống sẽ chỉ cấp READ_EXTERNAL_STORAGE tại thời điểm đó; tuy nhiên, nếu sau đó ứng dụng yêu cầu WRITE_EXTERNAL_STORAGE, thì hệ thống sẽ cấp ngay đặc quyền đó mà không cần nhắc người dùng.

Nội dung nghe nhìn

  • Khung này có thể tự tự động giảm âm thanh. Trong trường hợp này, khi một ứng dụng khác yêu cầu tiêu điểm bằng AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, ứng dụng có tiêu điểm sẽ giảm âm lượng nhưng thường không nhận được lệnh gọi lại onAudioFocusChange() và sẽ không mất tiêu điểm âm thanh. Các API mới có sẵn để ghi đè hành vi này cho các ứng dụng cần tạm dừng thay vì giảm âm lượng.
  • Khi người dùng nhận cuộc gọi điện thoại, các luồng nội dung đa phương tiện đang hoạt động sẽ tắt tiếng trong suốt thời gian cuộc gọi.
  • Mọi API liên quan đến âm thanh đều phải sử dụng AudioAttributes thay vì các loại luồng âm thanh để mô tả trường hợp sử dụng tính năng phát âm thanh. Tiếp tục chỉ sử dụng các loại luồng âm thanh để điều khiển âm lượng. Các cách sử dụng khác của loại luồng vẫn hoạt động (ví dụ: đối số streamType cho hàm khởi tạo AudioTrack không dùng nữa), nhưng hệ thống sẽ ghi lại điều này dưới dạng lỗi.
  • Khi sử dụng AudioTrack, nếu ứng dụng yêu cầu bộ đệm âm thanh đủ lớn, thì khung sẽ cố gắng sử dụng đầu ra bộ đệm sâu (nếu có).
  • Trong Android 8.0 (API cấp 26), cách xử lý sự kiện nút phát nội dung nghe nhìn sẽ khác:
    1. Cách xử lý các nút nội dung nghe nhìn trong một hoạt động trên giao diện người dùng không thay đổi: các hoạt động trên nền trước vẫn được ưu tiên khi xử lý các sự kiện nút nội dung nghe nhìn.
    2. Nếu hoạt động trên nền trước không xử lý sự kiện nút nội dung nghe nhìn, thì hệ thống sẽ chuyển sự kiện đó đến ứng dụng phát âm thanh cục bộ gần đây nhất. Trạng thái hoạt động, cờ và trạng thái phát của một phiên phát nội dung đa phương tiện không được xem xét khi xác định ứng dụng nào nhận được các sự kiện nút nội dung nghe nhìn.
    3. Nếu phiên phát nội dung nghe nhìn của ứng dụng đã được phát hành, hệ thống sẽ gửi sự kiện nút phát nội dung nghe nhìn đến MediaButtonReceiver của ứng dụng nếu có.
    4. Đối với mỗi trường hợp khác, hệ thống sẽ loại bỏ sự kiện nút nội dung nghe nhìn.

Thư viện gốc

Trong các ứng dụng nhắm đến Android 8.0 (API cấp 26), thư viện gốc sẽ không tải nữa nếu chứa bất kỳ phân đoạn tải nào có thể ghi và thực thi. Một số ứng dụng có thể ngừng hoạt động do thay đổi này nếu các ứng dụng đó có thư viện gốc có phân đoạn tải không chính xác. Đây là một biện pháp tăng cường bảo mật.

Để biết thêm thông tin, hãy xem phần Các phân đoạn có thể ghi và có thể thực thi.

Các thay đổi về trình liên kết gắn liền với cấp độ API mà ứng dụng nhắm mục tiêu. Nếu có thay đổi về trình liên kết ở cấp API mục tiêu, thì ứng dụng sẽ không thể tải thư viện. Nếu bạn đang nhắm đến một cấp độ API thấp hơn cấp độ API xảy ra thay đổi trình liên kết, logcat sẽ hiển thị cảnh báo.

Xử lý bộ sưu tập

Trong Android 8.0 (API cấp 26), Collections.sort() được triển khai trên List.sort(). Điều ngược lại là đúng trong Android 7.x (API cấp 24 và 25): Việc triển khai mặc định của List.sort() được gọi là Collections.sort().

Thay đổi này cho phép Collections.sort() tận dụng các phương thức triển khai List.sort() được tối ưu hoá, nhưng có các quy tắc ràng buộc sau:

  • Quá trình triển khai List.sort() không được gọi Collections.sort(), vì việc này sẽ dẫn đến tình trạng tràn ngăn xếp do đệ quy vô hạn. Thay vào đó, nếu muốn hành vi mặc định trong quá trình triển khai List, bạn nên tránh ghi đè sort().

    Nếu một lớp mẹ triển khai sort() không phù hợp, thì bạn có thể ghi đè List.sort() bằng cách triển khai dựa trên List.toArray(), Arrays.sort()ListIterator.set(). Ví dụ:

    @Override
    public void sort(Comparator<? super E> c) {
      Object[] elements = toArray();
      Arrays.sort(elements, c);
      ListIterator<E> iterator = (ListIterator<Object>) listIterator();
      for (Object element : elements) {
        iterator.next();
        iterator.set((E) element);
      }
    }

    Trong hầu hết trường hợp, bạn cũng có thể ghi đè List.sort() bằng cách triển khai uỷ quyền cho nhiều phương thức triển khai mặc định tuỳ thuộc vào cấp độ API. Ví dụ:

    @Override
    public void sort(Comparator<? super E> comparator) {
      if (Build.VERSION.SDK_INT <= 25) {
        Collections.sort(this);
      } else {
        super.sort(comparator);
      }
    }

    Nếu bạn chỉ làm việc này vì muốn có một phương thức sort() trên tất cả các cấp độ API, hãy cân nhắc đặt tên riêng cho phương thức đó, chẳng hạn như sortCompat(), thay vì ghi đè sort().

  • Collections.sort() hiện được tính là một nội dung sửa đổi cấu trúc trong quá trình triển khai Danh sách gọi sort(). Ví dụ: trong các phiên bản của nền tảng trước Android 8.0 (API cấp 26), việc lặp lại qua một ArrayList và gọi sort() trên đó một phần trong quá trình lặp lại sẽ gửi một ConcurrentModificationException nếu việc sắp xếp được thực hiện bằng cách gọi List.sort(). Collections.sort() không gửi một ngoại lệ.

    Thay đổi này giúp hành vi của nền tảng nhất quán hơn: Giờ đây, cả hai phương pháp đều dẫn đến ConcurrentModificationException.

Hành vi tải lớp

Android 8.0 (API cấp 26) kiểm tra để đảm bảo trình tải lớp không vi phạm các giả định về thời gian chạy khi tải các lớp mới. Các bước kiểm tra này được thực hiện cho dù lớp được tham chiếu từ Java (từ forName()), mã byte Dalvik hay JNI. Nền tảng này không chặn các lệnh gọi trực tiếp từ Java đến phương thức loadClass(), cũng như không kiểm tra kết quả của các lệnh gọi đó. Hành vi này không được ảnh hưởng đến hoạt động của trình tải lớp hoạt động tốt.

Nền tảng này sẽ kiểm tra để đảm bảo rằng chỉ số mô tả của lớp mà trình tải lớp trả về khớp với chỉ số mô tả dự kiến. Nếu chỉ số mô tả được trả về không khớp, nền tảng sẽ gửi ra lỗi NoClassDefFoundError và lưu trữ một thông báo chi tiết về sự khác biệt trong trường hợp ngoại lệ.

Nền tảng này cũng kiểm tra để đảm bảo rằng các chỉ số mô tả của các lớp được yêu cầu là hợp lệ. Bước kiểm tra này phát hiện các lệnh gọi JNI tải gián tiếp các lớp như GetFieldID(), truyền chỉ số mô tả không hợp lệ đến các lớp đó. Ví dụ: không tìm thấy trường có chữ ký java/lang/String vì chữ ký đó không hợp lệ; chữ ký phải là Ljava/lang/String;.

Tên này khác với lệnh gọi JNI đến FindClass(), trong đó java/lang/String là tên đủ điều kiện hợp lệ.

Android 8.0 (API cấp 26) không hỗ trợ việc nhiều trình tải lớp cố gắng xác định các lớp bằng cùng một đối tượng DexFile. Nếu bạn cố gắng làm như vậy, môi trường thời gian chạy Android sẽ gửi một lỗi InternalError kèm theo thông báo "Cố gắng đăng ký tệp dex <filename> bằng nhiều trình tải lớp".

DexFile API hiện không còn được dùng nữa và bạn nên sử dụng một trong các trình tải lớp nền tảng, bao gồm cả PathClassLoader hoặc BaseDexClassLoader.

Lưu ý: Bạn có thể tạo nhiều trình tải lớp tham chiếu đến cùng một vùng chứa tệp APK hoặc JAR từ hệ thống tệp. Việc làm như vậy thường không dẫn đến mức hao tổn bộ nhớ nhiều: Nếu các tệp DEX trong vùng chứa được lưu trữ thay vì nén, thì nền tảng có thể thực hiện thao tác mmap trên các tệp đó thay vì trực tiếp trích xuất các tệp đó. Tuy nhiên, nếu nền tảng phải trích xuất tệp DEX từ vùng chứa, thì việc tham chiếu tệp DEX theo cách này có thể tiêu tốn nhiều bộ nhớ.

Trong Android, tất cả trình tải lớp đều được coi là có khả năng chạy song song. Khi nhiều luồng chạy đua để tải cùng một lớp bằng cùng một trình tải lớp, luồng đầu tiên hoàn tất thao tác sẽ thắng và kết quả sẽ được dùng cho các luồng khác. Hành vi này xảy ra bất kể trình tải lớp có trả về cùng một lớp, trả về một lớp khác hay gửi một ngoại lệ. Nền tảng này sẽ tự động bỏ qua các ngoại lệ như vậy.

Thận trọng: Trong các phiên bản nền tảng thấp hơn Android 8.0 (API cấp 26), việc vi phạm các giả định này có thể dẫn đến việc xác định cùng một lớp nhiều lần, hỏng vùng nhớ khối xếp do nhầm lẫn lớp và các hiệu ứng không mong muốn khác.