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 API và hệ thống. Tài liệu này nêu bật một số thay đổi quan trọng mà bạn nên nắm rõ và lưu ý trong ứng dụng của mình.

Hầu hết những thay đổi này đều ảnh hưởng đến mọi ứ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 các ứng dụng nhắm đến Android 8.0. Để tăng tối đa sự rõ ràng, trang này được chia thành 2 phần: Các thay đổi đối với mọi ứng dụngCác thay đổ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 này về hành vi áp dụng cho tất cả ứng dụng khi chúng chạy trên nền tảng Android 8.0 (API cấp 26), bất kể cấp độ API mà các ứng dụng đó nhắm đến. Tất cả nhà phát triển nên xem xét những thay đổi này và sửa đổi ứng dụng của họ để hỗ trợ những thay đổi đó cho phù hợp (nếu phù hợp).

Giới hạn thực thi ở chế độ 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 đang hoạt động, hệ thống sẽ huỷ bỏ 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ẽ hạn chế 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 độ thoải mái mà chúng có thể 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 phát ngầm (tức là các thông báo truyền tin không dành riêng cho ứng dụng).

Theo mặc định, những hạn chế này chỉ áp dụng cho các ứ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 chưa nhắm đến O.

Android 8.0 (API cấp 26) cũng có những 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 các dịch vụ nền.
  • Phương thức Context.startForegroundService() mới bắt đầu một dịch vụ trên nền trước. Hệ thống cho phép các ứng dụng gọi Context.startForegroundService() ngay cả khi ứng dụng đang ở 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 bài viết Giới hạn thực thi trong nền.

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

Để duy trì thời lượng pin, trải nghiệm người dùng và tình trạng hệ thống, các ứng dụng ở chế độ nền sẽ ít nhận thông tin cập nhật vị trí hơn khi được sử dụng trên thiết bị chạy Android 8.0. Sự thay đổi này về hành vi ảnh hưởng đến tất cả ứng dụng nhận được 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 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.
  • Hãy 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 bài viết Giới hạn quyền truy cập 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 đây đố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ì đó là thông báo riêng tư, ngầm ẩn. Thay vào đó, bạn nên tạo lối tắt ứng dụng bằng phương thức requestPinShortcut() từ lớp ShortcutManager.
  • Giờ đây, ý định ACTION_CREATE_SHORTCUT có thể tạo lối tắt ứng dụng mà bạn quản lý bằng cách sử dụng lớp ShortcutManager. Ý định này cũng có thể tạo các lối tắt của 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 các lối tắt của trình chạy cũ.
  • Lối tắt được tạo bằng requestPinShortcut() và lối tắt được tạo trong một hoạt động xử lý ý định ACTION_CREATE_SHORTCUT hiện là lối tắt ứng dụng hoàn chỉnh. Do đó, các ứng dụng hiện có thể cập nhật bằng các phương thức trong ShortcutManager.
  • Lối tắt cũ vẫn giữ nguyên chức năng từ các phiên bản Android trước, nhưng bạn phải chuyển đổi chúng thành lối tắt ứng dụng theo cách thủ công trong ứng dụng của mình.

Để tìm hiểu thêm về những 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.

Bản địa 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 lẽ ra 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 hiện sử dụng Locale.getDefault(Category.DISPLAY) thay vì Locale.getDefault():

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

Sau đây là những thay đổi bổ sung 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 phù hợp với hành vi được ghi nhận trong tài liệu.
  • Quá trình 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 giờ. Do đó, việc 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 gặp hơn.

    Hiện tại, 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 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 dùng quyền SYSTEM_ALERT_WINDOW và 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 một ứng dụng nhắm đến Android 8.0 (API cấp 26), thì ứ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 các thay đổi về hành vi của Ứng dụng nhắm đến Android 8.0.

Phương thức 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 thao tác bằng bàn phím trong các ứng dụng Android đang trỗi dậy. Trong Android 8.0 (API cấp 26), chúng tôi đã đổi mới cách sử dụng bàn phím làm thiết bị đầu vào điều hướng, nhờ đó tạo ra một mô hình dễ dự đoán hơn, đáng tin cậy hơn cho việc điều hướng dựa trên mũi tên và thẻ.

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

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

    Nếu bạn không muốn đối tượng View sử dụng vùng nổi bật 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 đến setDefaultFocusHighlightEnabled() trong logic giao diện người dùng của ứng dụng.

  • Để kiểm thử xem chế độ nhập bằng bàn phím ảnh hưởng như thế nào đến tiêu điểm 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 Vẽ > Hiển thị ranh giới bố cục. Trong Android 8.0, tuỳ chọn này cho thấy biểu tượng "X" trên phần tử đang được lấy 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ụm điều hướng bàn phím, giúp người dùng dễ dàng di chuyển 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ợ điều hướng bằng bàn phím trong ứng dụng, hãy đọc hướng dẫn Hỗ trợ điều hướng bằng bàn phím.

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

Giờ đây, khi Khung tự động điền của Android hỗ trợ tích hợp sẵn 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òn có tác dụng nữa.
WebViewDatabase
  • Việc gọi clearFormData() không còn có tác dụng 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 về khả năng hỗ trợ tiếp cận:

  • Khung hỗ trợ tiếp cận hiện sẽ chuyển đổi tất cả cử chỉ nhấn đúp thành các thao tác ACTION_CLICK. Thay đổi này sẽ giúp TalkBack hoạt động giống với 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 chức năng xử lý cảm ứng tuỳ chỉnh, 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 của bạn sử dụng. Nếu TalkBack vẫn không nhận ra được những 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 mọi 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 của bạn dễ tiếp cận hơn, hãy xem bài viết Hỗ trợ tiếp cận.

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

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

  • Những yêu cầu OPTIONS không có nội dung sẽ có tiêu đề Content-Length: 0. Trước đây, chúng 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 vào sau tên máy chủ lưu trữ hoặc đơn vị quản lý. Ví dụ: đối tượng 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 mục tiêu địa chỉ (lược đồ, máy chủ lưu trữ và cổng) của một URL được yêu cầu. Do đó, lựa chọn proxy có thể chỉ 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ữ, tức là trường hợp sử dụng URI không hợp lệ. 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 đúng cách sẽ thấy một thông báo ADB: "URI example..com có nhãn trống trong tên máy chủ. Thuộc tính 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 sẽ 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.

  • Hoạt động 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) trong dòng Máy chủ lưu trữ khi gửi thông tin này đến một 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à cấp quyền proxy từ một yêu cầu qua đường hầm đến máy chủ proxy.

      Khi thiết lập đường hầm, hệ thống không còn gửi tiêu đề uỷ quyền proxy đến proxy Http(s)URLConnection đường hầm nữa. 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 tới 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 đườ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 SocketException nếu phương thức connect() đã thực thi trước đó không thành công.
    • DatagramSocket.connect() đặt một pendingSocketException nếu có lỗi nội bộ. Trước Android 8.0, lệnh gọi recv() tiếp theo sẽ gửi ra 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, giờ đây có thể truy cập được nếu các máy chủ đó chấp nhận giao thức ICMP Echo.
    • Đối với các máy chủ thực sự không thể truy cập, thay đổi này có nghĩa là mất gấp đôi lượng thời gian trước khi lệnh gọi trả về.

Bluetooth

Android 8.0 (API cấp 26) thực hiện các thay đổi sau đố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 về số lượng byte nhận được. Do đó, ứng dụng không nên dựa vào bất kỳ số lượng byte nào tối thiểu hoặc tối đa được trả về. Thay vào đó, các đối tượng này sẽ đánh giá độ dài của mảng thu được.
  • 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à ~60 byte.
  • Nếu một thiết bị từ xa không cung cấp phản hồi quét, thì hàm cũng có thể trả về dưới 60 byte.

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

Android 8.0 (API cấp 26) thực hiện một số điểm cải tiến đối với chế độ Cài đặt Wi-Fi để giúp bạn dễ dàng chọn mạng Wi-Fi mang lại trải nghiệm tốt nhất cho người dùng. Các thay đổi cụ thể bao gồm:

  • 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 hợp nhất và duy nhất cho một lựa chọn ưu tiên về Wi-Fi.
  • Trên các thiết bị tương thích, tính năng tự động kích hoạt Wi-Fi khi mạng đã lưu chất lượng cao ở gần.

Bảo mật

Android 8.0 có các thay đổi sau đây liên quan đến 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 quy trình thương lượng phiên bản giao thức TLS không chính xác, HttpsURLConnection không còn tìm cách giải quyết vấn đề quay lại sử dụng 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 cho phép chỉ dành cho những lệnh gọi được hiển thị qua Bionic. Mặc dù có một số lệnh gọi hệ thống khác được cung cấp khả năng tương thích ngược, nhưng bạn không nên sử dụng các lệnh gọi này.
  • Đối tượng WebView của ứng dụng hiện chạy ở chế độ đa tiến trình. 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 chứa nhằm tăng cường bảo mật.
  • Bạn không 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. Ứng dụng nên sử dụng sourceDir để lấy thư mục và không trực tiếp dựa vào định dạng thư mục.
  • Để biết thông tin về các tính năng nâng cao bảo mật liên quan đến việc sử dụng thư viện gốc, hãy xem Thư viện gốc.

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

  • Giá trị của chế độ cài đặt cũ INSTALL_NON_MARKET_APPS hiện luôn là 1. Để xác định xem 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ề là canRequestPackageInstalls().
  • Nếu bạn cố gắng thay đổi giá trị của INSTALL_NON_MARKET_APPS bằng setSecureSetting(), thì hệ thống sẽ trả về UnsupportedOperationException. Để 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 quy định hạn chế đối với 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ế đối với người dùng DISALLOW_INSTALL_UNKNOWN_SOURCES. Đối với 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, chế độ hạn chế người dùng DISALLOW_INSTALL_UNKNOWN_SOURCES sẽ tự động được bật, trừ phi chủ sở hữu hồ sơ đã vô hiệu hoá rõ ràng 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ề việc cài đặt ứng dụng không rõ danh tí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 các nguyên tắc về cách tăng cường tính bảo mật cho ứng dụng, 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ư cho nền tảng này.

  • Nền tảng này hiện 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 OTA lên phiên bản Android 8.0 (API cấp 26) (API cấp 26), 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ữ lại các giá trị trong số các lượt gỡ cài đặt sau OTA, nhà phát triển có thể liên kết các giá trị cũ với giá trị 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 thiết bị chạy Android 8.0, giá trị của ANDROID_ID hiện được xác định phạm vi cho mỗi khoá ký ứng dụng, cũng như trên mỗi 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ã Android (ngay cả 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ý giống nhau (và ứng dụng chưa được cài đặt trước phiên bản Android 8.0 qua OTA).
    • Giá trị của ANDROID_ID không thay đổi ngay cả khi bản cập nhật hệ thống làm thay đổi khoá ký gói.
    • Trên những thiết bị vận chuyển có 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 tiêu chuẩn và đơn giả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 duy nhất mà người dùng có thể đặt lại cho quảng cáo. API 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ẽ tạo ra một kết quả rỗng.

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

Nếu một ứng dụng cài đặt một Thread.UncaughtExceptionHandler không gọi đến Thread.UncaughtExceptionHandler mặc định, thì hệ thống sẽ không loại bỏ ứng dụng khi xảy ra trường hợp ngoại lệ chưa nắm bắt được. 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 tình huống này; trong các phiên bản nền tảng 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 phương thức triển khai Thread.UncaughtExceptionHandler tuỳ chỉnh tới trình xử lý mặc định; các ứng dụng tuân theo đề xuất này không bị ảnh hưởng bởi thay đổi trong Android 8.0.

Thay đổi chữ ký findViewById()

Mọi 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ó các hệ quả sau:

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

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

Trong các phiên bản Android trước, thành phần Trình cung cấp danh bạ cho phép nhà phát triển nhận dữ liệu sử dụng của từng người liên hệ. Dữ liệu sử dụng này cho biết thông tin của 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 cả số lần liên hệ và lần gần nhất liên hệ đó. Các ứng dụng yêu cầu quyền READ_CONTACTS có thể đọc dữ liệu này.

Các ứ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, truy vấn 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.

Sự thay đổi về hành vi này ả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 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 phù hợp 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 dành cho ứng dụng doanh nghiệp, bao gồm cả trình kiểm soát chính sách thiết bị (DPC). Các thay đổi 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 các 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.
  • Cải thiện trải nghiệm người dùng như cấp phép, thông báo, màn hình Gần đây và VPN luôn bật.

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

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

Những thay đổi này về hành vi 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 dựa trên Android 8.0 hoặc đặt targetSdkVersion thành Android 8.0 trở lên phải sửa đổi để hỗ trợ những hành vi này cho phù hợp (nếu phù hợp).

Cửa sổ cảnh báo

Các ứng dụng dùng quyền SYSTEM_ALERT_WINDOW không thể sử dụng các loại cửa sổ sau để 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 nữa:

Thay vào đó, các ứ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 thị cửa sổ cảnh báo cho ứng dụng của bạn, hãy lưu ý các đặc điểm sau đây 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 trình bày 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 các chế độ cài đặt để chặn một ứng dụng hiển thị 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ề việc thay đổi nội dung

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 ContentProvider hợp lệ cho đơn vị quản lý trong tất cả các URI. Việc xác định một ContentProvider hợp lệ có các quyền liên quan sẽ giúp bảo vệ ứng dụng của bạn khỏi những thay đổi về nội dung của ứng dụng độc hại, đồng thời giúp bạn không làm rò rỉ dữ liệu riêng tư có thể xảy ra cho các ứng dụng độc hại.

Xem tiêu điểm

Theo mặc định, các đối tượng View có thể nhấp vào hiện cũng có thể làm tâm điểm. Nếu bạn muốn một đối tượng View có thể nhấp vào nhưng không thể làm tâm đ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ó chứa chuỗi giá trị nhận dạng bản dựng OPR. Một số mẫu trùng khớp 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ề kết quả khớp mẫu như vậy:

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 nhận dạng sai như vậy, hãy sử dụng một chuỗi không phải OPR làm mẫu khớp cho trình duyệt Opera.

Bảo mật

Những 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 qua 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 các 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 các nguồn không xác định đã bị xoá; ở vị trí đó, 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 rõ nguồn gốc. Để 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 các nguyên tắc về cách tăng cường tính bảo mật cho ứng dụng, 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à 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 còn quyền 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 nên sử dụng AccountManager.newChooseAccountIntent() hoặc 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à phát hiện tài khoản, hãy xem phần Truy cập vào tài khoản và khả năng phát hiện trong phần API mới của tài liệu này.

Quyền riêng tư

Những thay đổi sau ả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 hoạt động nữa. Đây là một thay đổi giúp cải thiện quyền riêng tư trên nền tảng.
  • Để lấy thông tin kết nối mạng 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. 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 hồ sơ công việc nhận thông tin về hồ sơ chính. Khi người dùng đang ở 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 thuộc cùng một nhóm hồ sơ. Như trước đây, việc cố gắng 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 cấp 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 nhóm quyền đã đăng ký trong tệp kê khai.

Đối với các ứng dụng nhắm đến Android 8.0, chúng tôi đã khắc phục hành vi này. Ứng dụng chỉ được cấp các quyền mà ứng dụng đã yêu cầu rõ ràng. Tuy nhiên, sau khi người dùng cấp quyền cho ứng dụng, mọi 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 đồng thời cấp WRITE_EXTERNAL_STORAGE vì API 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ì tại thời điểm đó, hệ thống chỉ cấp READ_EXTERNAL_STORAGE. Tuy nhiên, nếu sau đó ứng dụng yêu cầu WRITE_EXTERNAL_STORAGE, thì hệ thống sẽ ngay lập tức cấp đặc quyền đó mà không nhắc người dùng.

Nội dung nghe nhìn

  • Khung này có thể tự thực hiện quá trình 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 tâm điểm bằng AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, ứng dụng có tâm đ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 quyền phát âm thanh. Các API mới được cung cấp để ghi đè hành vi này cho các ứng dụng cần tạm dừng thay vì giảm dần.
  • Khi người dùng nhận cuộc gọi điện thoại, các luồng nội dung nghe nhìn đang hoạt động sẽ tắt tiếng trong suốt cuộc gọi.
  • Tất cả các 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 sử dụng các loại luồng âm thanh chỉ cho các nút điều chỉnh âm lượng. Các cách sử dụng loại luồng khác 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 trường hợp này là lỗi.
  • Khi sử dụng AudioTrack, nếu ứng dụng yêu cầu một vùng đệm âm thanh đủ lớn, thì khung sẽ cố gắng sử dụng dữ liệu đầu ra của vùng đệm sâu nếu có.
  • Trong Android 8.0 (API cấp 26), cách xử lý các sự kiện nút nội dung đa phương tiện sẽ khác:
    1. Cách xử lý các nút nội dung đa phương tiệ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 xử lý các sự kiện nút đa phương tiệ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 đa phương tiện, thì hệ thống sẽ chuyển sự kiện này đến ứng dụng mà gần đây nhất đã phát âm thanh trên máy. Trạng thái đang 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 phát nội dung đa phương tiện.
    3. Nếu phiên phát nội dung đa phương tiệ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 đa phương tiện đến MediaButtonReceiver của ứng dụng (nếu có).
    4. Đối với mỗi trường hợp còn lại, hệ thống sẽ loại bỏ sự kiện nút phương tiệ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 vừa có thể ghi vừa có thể 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 với 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 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 được nhắm 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 nơi xảy ra thay đổi về trình liên kết, thì logcat sẽ hiển thị một 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 cũng đúng trong Android 7.x (API cấp 24 và 25): Phương thức triển khai mặc định của List.sort() có tên 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ó những hạn chế sau:

  • Việc triển khai List.sort() không được gọi Collections.sort(), vì làm như vậ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 thường có thể ghi đè List.sort() bằng phương thức triển khai được xây dựng 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 một phương thức triển khai uỷ quyền cho các phương thức triển khai mặc định khác nhau 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ỉ thực hiện mục sau vì muốn có một phương thức sort() trên mọi cấp độ API, hãy cân nhắc việc đặt một tên riêng biệt 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 thay đổi cấu trúc trong quá trình triển khai Danh sách có 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 ArrayList và gọi sort() trên nền tảng đó trong 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 trường hợp ngoại lệ.

    Thay đổi này giúp hành vi của nền tảng nhất quán hơn: Một trong hai phương thức hiện sẽ 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 phá vỡ các giả định về thời gian chạy khi tải các lớp mới. Những quy trình kiểm tra này được thực hiện để xem 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 như vậy. Hành vi này sẽ không ả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 chỉ số mô tả của lớp mà trình tải lớp trả về khớp với mã mô tả dự kiến. Nếu chỉ số mô tả được trả về không khớp, nền tảng sẽ đưa ra lỗi NoClassDefFoundError và lưu trữ một thông báo chi tiết về sự khác biệt cho trường hợp ngoại lệ này.

Nền tảng này cũng sẽ kiểm tra để đảm bảo rằng 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 gián tiếp tải các lớp (chẳng hạn như GetFieldID()), chuyển giá trị mô tả không hợp lệ đến các lớp đó. Ví dụ: không tìm thấy một trường có chữ ký java/lang/String vì chữ ký đó không hợp lệ. Trường này phải là Ljava/lang/String;.

Giá trị này khác với lệnh gọi JNI cho 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 có nhiều trình tải lớp cố gắng xác định các lớp bằng cách sử dụng cùng một đối tượng DexFile. Nếu làm như vậy, môi trường thời gian chạy Android sẽ gửi lỗi InternalError với thông báo "Try to registration file dex <filename> với nhiều trình tải lớp".

Ngừng sử dụng DexFile API và bạn nên dùng một trong các trình tải lớp của 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. Cách làm này thông thường sẽ không gây ra nhiều hao tổn bộ nhớ: Nếu các tệp DEX trong vùng chứa được lưu trữ thay vì được 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, việc tham chiếu một tệp DEX theo cách này có thể sẽ tốn nhiều bộ nhớ.

Trong Android, tất cả các trình tải lớp đều được coi là có khả năng tải 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 thành thao tác sẽ chiến 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 trả về một ngoại lệ. Nền tảng này sẽ ngầm bỏ qua các trường hợp 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, lỗi vùng nhớ khối xếp do nhầm lẫn về lớp và các tác động không mong muốn khác.