Giới thiệu một số tính năng mới trong Android O (Phần IV)
Bài đăng này đã không được cập nhật trong 3 năm
Tiếp theo phần trước, ta sẽ tiếp tục tìm hiểu những thay đổi của Android O so với các phiên bản trước. Lần này ta sẽ tìm hiểu về các ứng dụng target đến Android O
Những thay đổi hành vi này chỉ áp dụng cho các ứng dụng đang nhắm mục tiêu nền tảng O trở lên. Ứng dụng thiết lập targetSdkVersion cho Android O trở lên phải sửa đổi ứng dụng của họ để hỗ trợ các hành vi này đúng cách, nếu có thể áp dụng cho ứng dụng.
Cửa sổ cảnh báo
Các ứng dụng sử dụng quyền SYSTEM_ALERT_WINDOW không còn có thể sử dụng các loại cửa sổ sau để hiển thị cửa sổ cảnh báo trên các ứng dụng và cửa sổ hệ thống khác:
TYPE_PHONE
TYPE_PRIORITY_PHONE
TYPE_SYSTEM_ALERT
TYPE_SYSTEM_OVERLAY
TYPE_SYSTEM_ERROR
Thay vào đó, ứng dụng phải sử dụng loại cửa sổ mới có tên TYPE_APPLICATION_OVERLAY .
Khi sử dụng kiểu 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 ý đến 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 thay đổi kích thước cửa sổ sử dụng loại cửa sổ TYPE_APPLICATION_OVERLAY để cải tiến 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 cài đặt để chặn một ứng dụng hiển thị các cửa sổ cảnh báo được hiển thị bằng kiểu cửa sổ TYPE_APPLICATION_OVERLAY .
Thông báo Content có thay đổi
Android O thay đổi cách ContentResolver.notifyChange()
và registerContentObserver(Uri, boolean, ContentObserver)
cư xử cho các ứng dụng nhắm mục tiêu đến Android O.
Các API này giờ đây yêu cầu một ContentProvider hợp lệ được định nghĩa cho quyền hạn trong tất cả Uris. Xác định ContentProvider hợp lệ với các quyền thích hợp sẽ giúp bảo vệ ứng dụng của bạn chống lại thay đổi nội dung từ các ứng dụng độc hại và ngăn bạn khỏi bị rò rỉ dữ liệu cá nhân tiềm ẩn đến các ứng dụng độc hại.
View focus
Các đối tượng View mà có thể click cũng có thể được focus theo mặc định. Nếu bạn muốn một đối tượng View được click nhưng không phải là focusable, hãy thiết lập thuộc tính android:focusable thành false trong file XML layout có chứa View hoặc pass false để setFocusable()
trong logic UI của ứng dụng của bạn.
Bảo mật
Nếu cấu hình bảo mật mạng của ứng dụng không hỗ trợ lưu lượng truy cập thông thường, các đối tượng WebView của ứng dụng của bạn không thể truy cập trang web qua HTTP. Mỗi đối tượng WebView phải sử dụng HTTPS thay thế.
Để biết thêm các nguyên tắc về làm cho ứng dụng của bạn an toàn hơn, xem Bảo mật dành cho Nhà phát triển Android .
Truy cập tài khoản và khả năng khám phá
Ứng dụng không còn có thể truy cập vào tài khoản người dùng trừ khi người xác thực sở hữu tài khoản hoặc người dùng cấp quyền truy cập đó. Sự cho phép của GET_ACCOUNTS không còn nữa. Để được cấp quyền truy cập vào một tài khoản, các ứng dụng phải sử dụng AccountManager.newChooseAccountIntent()
hoặc một phương pháp xác thực cụ thể. Sau khi 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 O deprecate LOGIN_ACCOUNTS_CHANGED_ACTION . Thay vào đó Apps nên sử dụng addOnAccountsUpdatedListener()
để nhận cập nhật các 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 tài khoản và khả năng khám phá, hãy xem phần Truy cập và Khả năng khám phá Tài khoản trong phần API mới của tài liệu này.
Riêng tư
Những thay đổi sau ảnh hưởng đến quyền riêng tư trong Android O.
- Các thuộc tính của hệ thống net.dns1 , net.dns2 , net.dns3 , và net.dns4 không còn tồn tại nữa, một thay đổi cải thiện sự riêng tư trên nền tảng này.
- Để có được thông tin mạng như máy chủ DNS, các ứng dụng có quyền ACCESS_NETWORK_STATE có thể đăng ký một đối tượng NetworkRequest hoặc NetworkCallback . Các lớp này có sẵn trong Android 5.0 (API cấp 21) trở lên.
- Build.SERIAL không được dùng nữa. Các ứng dụng cần biết số serial của phần cứng nên sử dụng phương thức
Build.getSerial()
, đòi hỏi sự cho phép READ_PHONE_STATE . - API LauncherApps không còn cho phép ứng dụng dùng work profile nhưng có thể lấy thông tin về profile chính. Khi người dùng ở trong work profile, API LauncherApps hoạt động như thể không có ứng dụng nào được cài đặt trong các cấu hình khác trong cùng một nhóm profile. Như trước đây, những nỗ lực để truy cập các profile không liên quan gây ra SecurityExceptions.
Quyền
Trước Android O, nếu một ứng dụng yêu cầu sự cho phép trong thời gian chạy và sự cho phép đã được cấp, hệ thống cũng đã cấp không chính xác cho ứng dụng phần còn lại của các quyền thuộc cùng nhóm quyền và được đăng ký trong tệp Manifest.
Đối với ứng dụng nhắm mục tiêu Android O, hành vi này đã được sửa chữa. Ứng dụng chỉ được cấp phép mà nó đã yêu cầu rõ ràng. Tuy nhiên, khi người dùng cấp phép cho ứng dụng, tất cả các yêu cầu cấp phép tiếp theo trong nhóm quyền đó sẽ được cấp tự động.
Ví dụ: giả sử ứng dụng liệt kê cả READ_EXTERNAL_STORAGE và WRITE_EXTERNAL_STORAGE trong tệp Manifest của nó. Ứng dụng yêu cầu READ_EXTERNAL_STORAGE và người dùng cấp cho nó. Nếu ứng dụng nhắm mục tiêu đến mức API 24 hoặc thấp hơn, hệ thống cũng cấp WRITE_EXTERNAL_STORAGE cùng một lúc, bởi vì nó thuộc cùng một nhóm quyền lưu trữ STORAGE và cũng được đăng ký trong manifest. Nếu ứng dụng nhắm mục tiêu Android O, hệ thống chỉ cấp cho READ_EXTERNAL_STORAGE vào thời điểm đó; Tuy nhiên, nếu ứng dụng sau đó yêu cầu WRITE_EXTERNAL_STORAGE , hệ thống sẽ cấp ngay cho đặc quyền đó mà không cần nhắc người dùng.
Phương tiện truyền thông
- Framework thực hiện việc ducking âm thanh. Các ứng dụng không mất focus trong trường hợp AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK . Các API mới có sẵn cho các ứng dụng cần tạm dừng thay vì ducking. Lưu ý rằng hành vi này không được triển khai trong bản phát hành Xem trước 1 của Android O.
- Khi người dùng thực hiện cuộc gọi điện thoại, các luồng phương tiện đang hoạt động sẽ tắt tiếng trong suốt thời gian cuộc gọi.
- Tất cả các API có liên quan đến âm thanh nên sử dụng
AudioAttributes
thay vì các loại luồng âm thanh để mô tả trường hợp sử dụng phát lại âm thanh. Tiếp tục sử dụng các loại luồng âm thanh chỉ dành cho kiểm soát âm lượng. Các cách sử dụng khác của các loại luồng (ví dụ như AudioTrack constructor không dùng nữa) vẫn hoạt động, nhưng hệ thống ghi lại lỗi này như một lỗi. - Khi sử dụng AudioTrack , nếu ứng dụng yêu cầu bộ đệm âm thanh đủ lớn, khung sẽ cố gắng sử dụng đầu ra đệm sâu nếu có.
- Trên Android O việc xử lý sự kiện nút phương tiện truyền thông là khác nhau: 1. Xử lý các nút phương tiện trên Giao diện người dùng không thay đổi: các Activity tiền cảnh vẫn được ưu tiên trong việc xử lý các nút phương tiện. 2. Nếu Activity tiền cảnh không xử lý nút phương tiện, hệ thống sẽ định tuyến các nút phương tiện đến ứng dụng gần đây nhất đã phát âm thanh cục bộ. Trạng thái hoạt động, cờ và trạng thái phát lại của phiên media không còn được xem xét khi xác định ứng dụng nào nhận được sự kiện nút phương tiện. Phiên truyền thông có thể nhận các sự kiện nút media ngay cả sau khi ứng dụng gọi setActive (false) . 3. Nếu phiên truyền thông của ứng dụng đã được phát hành , hệ thống sẽ gửi sự kiện nút phương tiện đến MediaButtonReceiver của ứng dụng, nếu nó 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 media. Không play bất cứ cái gì còn hơn là chơi các ứng dụng sai. Phương pháp định tuyến nút phương tiện truyền thông mới được tóm tắt trong biểu đồ sau:
Thư viện Native
Trong ứng dụng nhắm mục tiêu Android O, các thư viện native không còn tải nếu chúng có bất kỳ phân đoạn tải nào có thể ghi và thực thi được. Một số ứng dụng có thể ngừng hoạt động do thay đổi này nếu chúng có thư viện native có phân đoạn tải không chính xác. Đây là một biện pháp làm cứng an toàn.
Để biết thêm thông tin, xem Đoạn ghi và Thực thi .
Giống như các bản xem trước, Android O cũng làm cho tất cả các vấn đề liên quan đến linker trở nên rõ ràng hơn. Thay đổi liên kết được gắn với cấp độ API mà một ứng dụng nhắm mục tiêu. Nếu có sự thay đổi của trình liên kết ở cấp API được nhắm mục tiêu, ứng dụng không thể tải thư viện. Nếu bạn đang nhắm mục tiêu một mức API thấp hơn mức API khi thay đổi liên kết xảy ra, logcat sẽ hiển thị cảnh báo. Trong quá trình phát hành bản xem trước, các vấn đề liên quan đến trình liên kết không chỉ xuất hiện trong logcat mà còn hiển thị dưới dạng Toasts. Thay đổi này cải thiện khả năng hiển thị các vấn đề trước mức API mà cảnh báo trở thành lỗi.
Xử lý Collection
Trong Android O, Collections.sort()
được implements trên List.sort()
. Sự ngược lại là đúng trong Android 7.x (các mức API 24 và 25): Implements mặc định của List.sort()
được gọi đến Collections.sort()
.
Sự thay đổi này cho phép Collections.sort()
tận dụng tối ưu việc triển khai List.sort()
, nhưng có các ràng buộc sau:
- Thực thi của
List.sort()
không được gọiCollections.sort()
, bởi vì làm như vậy sẽ dẫn đến stack overflow do đệ quy vô hạn. Thay vào đó, nếu bạn muốn hành vi mặc định trong quá trình triển khai List , bạn nên tránh sort() . Nếu một lớp cha thực hiện sort() không phù hợp, thường là tốt để ghi đèList.sort()
với một thực thi được xây dựng trên đầu củaList.toArray()
,Arrays.sort()
và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 các trường hợp, bạn cũng có thể ghi đè List.sort()
với một triển khai thực hiện ủy nhiệm cho các cài đặt mặc định khác nhau tùy 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 đang dùng cách thứ 2 chỉ vì bạn muốn có một phương pháp sort() có sẵn trên tất cả các cấp độ API, hãy xem xét cho nó một tên độc nhất, chẳng hạn như sortCompat()
, thay vì overriding sort() .
Collections.sort()
bây giờ được tính là một sửa đổi cấu trúc trong việc triển khai danh sách mà gọi là sort() . Ví dụ: trong các phiên bản trước Android O, lặp lại qua ArrayList và gọi sort() trên đó qua một lần lặp đi lặp lại sẽ ném mộtConcurrentModificationException
nếu việc phân loại đã được thực hiện bằng cách gọiList.sort()
.Collections.sort()
không throw exception. Sự thay đổi này làm cho hành vi của nền tảng trở nên nhất quán: Cách tiếp cận hiện nay dẫn đến ConcurrentModificationException .
Class-loading
Android O kiểm tra để đảm bảo rằng bộ nạp 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. Các kiểm tra này được thực hiện cho dù lớp được tham chiếu từ Java (từ forName() ), bytecode Dalvik hay JNI. Nền tảng này không chặn các cuộc gọi trực tiếp từ Java đến phương thức loadClass()
, cũng không kiểm tra kết quả của các cuộc gọi như vậy. Hành vi này không ảnh hưởng đến hoạt động của bộ tải lớp cư xử tốt.
Nền tảng kiểm tra rằng mô tả của lớp mà trình nạp lớp trả về phù hợp với descriptor dự kiến. Nếu bộ mô tả trả về không khớp, nền tảng này sẽ phát ra lỗi NoClassDefFoundError
và lưu trữ ngoại lệ một thông báo chi tiết ghi nhận sự khác biệt.
Nền tảng cũng kiểm tra rằng mô tả của các lớp được yêu cầu là hợp lệ. Kiểm tra này bắt JNI gọi rằng các lớp tải gián tiếp như GetFieldID() , chuyển descriptor không hợp lệ đến các lớp học. Ví dụ: không tìm thấy trường có chữ ký java/lang/String vì chữ ký đó không hợp lệ; Cần Ljava/lang/String; .
Điều này khác với cuộc gọi JNI đến FindClass() nơi java/lang/String là một tên hợp lệ đầy đủ.
Android O không hỗ trợ có nhiều trình kết nối lớp cố gắng định nghĩa các lớp học bằng cách sử dụng cùng một đối tượng DexFile. Một cố gắng làm như vậy làm cho trình chạy Android ném lỗi InternalError với thông báo "Attempt to register dex file <filename> with multiple class loaders".
DexFile API hiện không được dùng nữa và bạn nên sử dụng một trong những trình nạp 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 nạp lớp tham chiếu cùng một tệp APK hoặc tệp JAR chứa từ hệ thống tệp. Làm như vậy bình thường không dẫn đến nhiều bộ nhớ trên không: Nếu các tệp DEX trong thùng chứa được lưu trữ thay vì nén, thì nền tảng này có thể thực hiện thao tác mmap trên chúng thay vì trích xuất trực tiếp chúng. Tuy nhiên, nếu nền tảng phải trích xuất tệp DEX từ vùng chứa, tham chiếu tệp DEX theo cách này có thể tiêu tốn rất nhiều bộ nhớ.
Trong Android, tất cả các bộ nạp lớp đều được coi là có khả năng song song. Khi nhiều threads tải cùng một lớp với cùng bộ nạp lớp, threads đầu tiên để hoàn thành thao tác sẽ thắng, và kết quả được sử dụng cho các threads khác. Hành vi này xảy ra bất kể trình nạp lớp đã trả lại cùng một lớp, trả về một lớp khác hay ném ra một exception. Nền tảng âm thầm bỏ qua những trường hợp ngoại lệ như vậy.
Chú ý: Trong các phiên bản của nền tảng thấp hơn Android O, việc phá vỡ các giả định này có thể dẫn đến việc xác định cùng lớp nhiều lần, heap bị corrupt do sự nhầm lẫn trong lớp và các tác động không mong muốn khác.
(Lược dịch từ https://developer.android.com/preview/behavior-changes.html?hl=vi#o-apps)
Vậy là chúng ta đã cùng xem qua những thay đổi của Android O so với các phiên bản trước đó. Hi vọng bài viết này có thể giúp bạn hiểu được những thay đổi đó để có thể xây dựng app tốt hơn.
All rights reserved