Intent
là một đối tượng thông báo mà bạn có thể dùng để yêu cầu một hành động
từ một thành phần ứng dụng khác.
Mặc dù ý định tạo điều kiện cho việc giao tiếp giữa các thành phần theo một số cách, có 3
các trường hợp sử dụng cơ bản:
- Bắt đầu một hoạt động
Activity
đại diện cho một màn hình trong ứng dụng. Bạn có thể bắt đầu một thực thể củaActivity
bằng cách truyềnIntent
đếnstartActivity()
.Intent
mô tả hoạt động để bắt đầu và mang theo mọi dữ liệu cần thiết.Nếu bạn muốn nhận kết quả từ hoạt động khi hoạt động kết thúc, gọi
startActivityForResult()
. Hoạt động của bạn nhận được kết quả dưới dạng một đối tượngIntent
riêng biệt trong lệnh gọi lạionActivityResult()
của hoạt động. Để biết thêm thông tin, hãy xem hướng dẫn về Hoạt động. - Bắt đầu một dịch vụ
Service
là một thành phần thực hiện các thao tác ở chế độ nền mà không có giao diện người dùng. Bạn có thể bắt đầu một dịch vụ với Android 5.0 (API cấp 21) trở lên cùng vớiJobScheduler
. Thông tin khác vềJobScheduler
, hãy xemAPI-reference documentation
Đối với các phiên bản trước Android 5.0 (API cấp 21), bạn có thể bắt đầu một dịch vụ bằng cách sử dụng của lớp
Service
. Bạn có thể bắt đầu một dịch vụ để thực hiện thao tác một lần (chẳng hạn như tải tệp xuống) bằng cách truyền mộtIntent
đếnstartService()
.Intent
mô tả dịch vụ để bắt đầu và mang theo mọi dữ liệu cần thiết.Nếu dịch vụ được thiết kế theo giao diện máy khách-máy chủ, bạn có thể liên kết với dịch vụ từ một thành phần khác bằng cách truyền
Intent
đếnbindService()
. Để biết thêm thông tin, hãy xem hướng dẫn về Dịch vụ. - Phân phối thông báo
Thông báo truyền tin là một thông báo mà bất kỳ ứng dụng nào cũng có thể nhận được. Hệ thống này phân phối nhiều thông báo cho các sự kiện của hệ thống, chẳng hạn như khi hệ thống khởi động hoặc thiết bị bắt đầu sạc. Bạn có thể phân phối thông báo truyền tin đến các ứng dụng khác bằng cách truyền
Intent
đếnsendBroadcast()
hoặcsendOrderedBroadcast()
.
Phần còn lại của trang này giải thích cách hoạt động của ý định và cách sử dụng ý định. Để biết thông tin liên quan, hãy xem Tương tác với ứng dụng khác và Chia sẻ nội dung.
Các loại ý định
Có hai loại ý định:
- Ý định tường minh chỉ định thành phần nào của ứng dụng sẽ đáp ứng ý định bằng cách chỉ định một
ComponentName
đầy đủ. Bạn sẽ thường dùng một ý định tường minh để bắt đầu một thành phần trong ứng dụng của riêng bạn vì bạn biết tên lớp của hoạt động hoặc dịch vụ bạn muốn bắt đầu. Cho ví dụ: bạn có thể bắt đầu một hoạt động mới trong ứng dụng để phản hồi một hành động của người dùng hoặc bắt đầu dịch vụ tải tệp xuống ở chế độ nền. - Ý định ngầm ẩn không khai báo tên của một thành phần cụ thể mà khai báo một thao tác chung thực hiện, điều này cho phép thành phần của một ứng dụng khác xử lý nó. Ví dụ: nếu bạn muốn hiển thị cho người dùng một vị trí trên bản đồ, bạn có thể sử dụng ý định ngầm ẩn để yêu cầu một vị trí khác ứng dụng hiển thị một vị trí được chỉ định trên bản đồ.
Hình 1 cho thấy cách một ý định được sử dụng khi bắt đầu một hoạt động. Khi
Đối tượng Intent
đặt tên rõ ràng cho một thành phần hoạt động cụ thể, hệ thống
sẽ khởi động ngay thành phần đó.
![](https://developer.android.google.cn/static/images/components/intent-filters_2x.png?authuser=9&hl=vi)
Hình 1. Cách thức của ý định ngầm ẩn
được phân phối qua hệ thống để bắt đầu một hoạt động khác: [1] Hoạt động A tạo ra một
Intent
cùng với nội dung mô tả hành động và chuyển thành phần này đến startActivity()
. [2] Hệ thống Android tìm kiếm tất cả
ứng dụng cho bộ lọc ý định khớp với ý định. Khi tìm thấy kết quả trùng khớp, [3] hệ thống
khởi động hoạt động so khớp (Hoạt động B) bằng cách gọi phương thức onCreate()
và truyền phương thức Intent
.
Khi bạn sử dụng một ý định ngầm ẩn, hệ thống Android sẽ tìm thành phần thích hợp để bắt đầu
bằng cách so sánh nội dung của ý định với bộ lọc ý định được khai báo trong tệp kê khai của các ứng dụng khác trên
thiết bị. Nếu ý định khớp với bộ lọc ý định, hệ thống sẽ khởi động và phân phối thành phần đó
đối tượng Intent
. Nếu nhiều bộ lọc ý định tương thích, hệ thống
sẽ hiện hộp thoại để người dùng có thể chọn ứng dụng sẽ sử dụng.
Bộ lọc ý định là một biểu thức trong tệp kê khai của ứng dụng chỉ định loại ý định mà thành phần muốn nhận. Ví dụ: bằng cách khai báo bộ lọc ý định cho một hoạt động, bạn giúp các ứng dụng khác có thể trực tiếp bắt đầu hoạt động của bạn với một loại ý định nhất định. Tương tự, nếu bạn không khai báo bộ lọc ý định nào cho một hoạt động, thì bạn có thể bắt đầu hoạt động đó chỉ với một ý định tường minh.
Thận trọng: Để đảm bảo rằng ứng dụng của bạn được an toàn, hãy luôn luôn
sử dụng
khi bắt đầu Service
và không
khai báo bộ lọc ý định cho dịch vụ của bạn. Việc sử dụng ý định ngầm ẩn để bắt đầu một dịch vụ
mối nguy hiểm về bảo mật vì bạn không thể chắc chắn dịch vụ nào sẽ phản hồi ý định,
và người dùng không thể thấy dịch vụ nào bắt đầu. Kể từ Android 5.0 (API cấp 21), hệ thống
ném một trường hợp ngoại lệ nếu bạn gọi bindService()
có ý định ngầm ẩn.
Xây dựng ý định
Đối tượng Intent
mang thông tin mà hệ thống Android sử dụng
để xác định xem cần bắt đầu thành phần nào (chẳng hạn như tên hoặc thành phần chính xác của thành phần
danh mục sẽ nhận được ý định), cùng với thông tin mà thành phần người nhận sử dụng trong đó
thực hiện đúng hành động (chẳng hạn như hành động cần thực hiện và dữ liệu cần thực hiện).
Thông tin chính có trong Intent
như sau:
- Tên thành phần
- Tên của thành phần cần bắt đầu.
Việc này không bắt buộc nhưng nó là phần thông tin quan trọng giúp tạo ý định explicit (rõ ràng), nghĩa là ý định chỉ nên được gửi đến thành phần ứng dụng được xác định theo tên thành phần. Nếu không có tên thành phần, ý định sẽ là ngầm ẩn và hệ thống sẽ quyết định thành phần nào sẽ nhận ý định dựa trên thông tin về ý định khác (chẳng hạn như hành động, dữ liệu và danh mục – được mô tả bên dưới). Nếu bạn cần bắt đầu một thành phần trong ứng dụng, bạn nên chỉ định tên thành phần.
Lưu ý: Khi bắt đầu
Service
, luôn chỉ định tên thành phần. Nếu không, bạn không thể chắc chắn dịch vụ nào sẽ phản hồi ý định và người dùng không thể biết dịch vụ nào bắt đầu.Trường này của
Intent
là một Đối tượngComponentName
mà bạn có thể chỉ định bằng cách sử dụng một đối tượng đầy đủ tên lớp đủ điều kiện của thành phần mục tiêu, bao gồm cả tên gói của ứng dụng, ví dụ:com.example.ExampleActivity
. Bạn có thể đặt tên thành phần bằngsetComponent()
,setClass()
,setClassName()
, hoặc bằng Hàm khởi tạoIntent
. - Hành động
- Một chuỗi chỉ định thao tác chung cần thực hiện (chẳng hạn như view hoặc pick).
Trong trường hợp ý định truyền tin, đây là hành động đã diễn ra và đang được báo cáo. Hành động phần lớn quyết định cách cấu trúc phần còn lại của ý định, cụ thể là thông tin có trong dữ liệu và các dữ liệu bổ sung.
Bạn có thể chỉ định các hành động của riêng mình để ý định trong ứng dụng (hoặc để người khác sử dụng ứng dụng để gọi các thành phần trong ứng dụng), nhưng bạn thường chỉ định hằng số hành động do lớp
Intent
hoặc các lớp khung khác xác định. Sau đây là một số các thao tác phổ biến để bắt đầu một hoạt động:ACTION_VIEW
- Sử dụng hành động này trong một ý định bằng
startActivity()
khi bạn có một số thông tin một hoạt động có thể hiển thị với người dùng, chẳng hạn như ảnh để xem trong ứng dụng thư viện hoặc địa chỉ để chế độ xem trong ứng dụng bản đồ. ACTION_SEND
- Còn được gọi là ý định chia sẻ, bạn nên sử dụng ý định này trong một ý định với
startActivity()
khi bạn có một số dữ liệu mà người dùng có thể chia sẻ thông qua một ứng dụng khác, chẳng hạn như ứng dụng email hoặc ứng dụng chia sẻ qua mạng xã hội.
Xem tài liệu tham khảo về lớp
Intent
để biết thêm thông tin hằng số xác định các hành động chung. Các thao tác khác được xác định ở nơi khác trong khung Android, chẳng hạn như trongSettings
để thao tác mở màn hình cụ thể trong ứng dụng Cài đặt của hệ thống.Bạn có thể chỉ định thao tác cho một ý định bằng
setAction()
hoặc bằng hàm khởi tạoIntent
.Nếu bạn xác định các hành động của riêng mình, hãy nhớ bao gồm tên gói của ứng dụng làm tiền tố, như được minh hoạ trong ví dụ sau:
Kotlin
const val ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL"
Java
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
- Dữ liệu
- URI (đối tượng
Uri
) tham chiếu dữ liệu đến được thực hiện trên và/hoặc Loại MIME của dữ liệu đó. Loại dữ liệu được cung cấp thường được quyết định bởi hành động của ý định. Cho ví dụ: nếu hành động làACTION_EDIT
, thì dữ liệu phải chứa URI của tài liệu cần chỉnh sửa.Khi tạo một ý định, bạn thường cần chỉ định loại dữ liệu (loại MIME) ngoài URI của dữ liệu. Ví dụ: một hoạt động có thể hiển thị hình ảnh sẽ không thể để phát tệp âm thanh, mặc dù định dạng URI có thể tương tự nhau. Việc chỉ định loại MIME cho dữ liệu sẽ giúp Android hệ thống sẽ tìm thành phần phù hợp nhất để tiếp nhận ý định của bạn. Tuy nhiên, loại MIME đôi khi có thể được suy ra từ URI – đặc biệt là khi dữ liệu là URI
content:
. URIcontent:
cho biết dữ liệu nằm trên thiết bị và được kiểm soát bởiContentProvider
để hệ thống có thể nhìn thấy loại MIME dữ liệu.Để chỉ đặt URI dữ liệu, hãy gọi
setData()
. Để chỉ đặt loại MIME, hãy gọisetType()
. Nếu cần, bạn có thể đặt cả hai một cách rõ ràng bằngsetDataAndType()
.Thận trọng: Nếu bạn muốn đặt cả loại URI và MIME, không gọi
setData()
vàsetType()
vì mỗi giá trị đều rỗng giá trị của thành phần còn lại. Luôn sử dụngsetDataAndType()
để đặt cả hai Loại URI và MIME. - Danh mục
- Một chuỗi chứa thông tin bổ sung về loại thành phần
sẽ xử lý ý định. Bất kỳ số lượng nội dung mô tả danh mục nào cũng có thể
được đặt trong một ý định, nhưng hầu hết ý định không cần có danh mục.
Dưới đây là một số danh mục phổ biến:
CATEGORY_BROWSABLE
- Hoạt động mục tiêu cho phép trình duyệt web khởi động chính nó để hiển thị dữ liệu tham chiếu bằng một đường liên kết, chẳng hạn như hình ảnh hoặc nội dung email.
CATEGORY_LAUNCHER
- Hoạt động là hoạt động ban đầu của một tác vụ và được liệt kê trong trình chạy ứng dụng của hệ thống.
Xem mô tả lớp
Intent
để biết danh sách đầy đủ danh mục.Bạn có thể chỉ định một danh mục bằng
addCategory()
.
Những thuộc tính nêu trên (tên thành phần, hành động, dữ liệu và danh mục) đại diện cho việc xác định các đặc điểm của một ý định. Bằng cách đọc các thuộc tính này, hệ thống Android có thể phân giải xem nên khởi động thành phần ứng dụng nào. Tuy nhiên, một ý định có thể mang thông tin bổ sung không ảnh hưởng cách phân giải thành phần ứng dụng. Một ý định cũng có thể cung cấp các thông tin sau:
- Thông tin khác
- Các cặp khoá-giá trị chứa thông tin bổ sung cần thiết để hoàn thành
hành động được yêu cầu.
Giống như một số thao tác sử dụng các loại URI dữ liệu cụ thể, một số thao tác cũng sử dụng các dữ liệu bổ sung cụ thể.
Bạn có thể thêm dữ liệu bổ sung bằng nhiều phương thức
putExtra()
, mỗi khóa sẽ chấp nhận hai tham số: tên khoá và giá trị. Bạn cũng có thể tạo đối tượngBundle
có tất cả dữ liệu bổ sung, sau đó chènBundle
trongIntent
vớiputExtras()
.Ví dụ: khi tạo ý định gửi email bằng
ACTION_SEND
, bạn có thể chỉ định người nhận đến bằngEXTRA_EMAIL
rồi chỉ định chủ đề bằng KhoáEXTRA_SUBJECT
.Lớp
Intent
chỉ định nhiều hằng sốEXTRA_*
cho các kiểu dữ liệu được chuẩn hoá. Nếu bạn cần khai báo các khoá bổ sung của riêng mình (đối với ý định ứng dụng của bạn nhận được), hãy nhớ bao gồm tên gói của ứng dụng làm tiền tố, như được minh hoạ trong ví dụ sau:Kotlin
const val EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS"
Java
static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";
Thận trọng: Không sử dụng
Parcelable
hoặc Dữ liệuSerializable
khi gửi một ý định mà bạn muốn một ứng dụng khác để nhận. Nếu một ứng dụng cố gắng truy cập dữ liệu trong đối tượngBundle
nhưng không có quyền truy cập vào lớp được phân vùng hoặc tuần tự, hệ thống sẽ đưa ra mộtRuntimeException
- Cờ
- Cờ được định nghĩa trong lớp
Intent
có chức năng dưới dạng siêu dữ liệu cho ý định. Cờ có thể hướng dẫn hệ thống Android cách khởi chạy một hoạt động (ví dụ: việc cần làm hoạt động phải thuộc về và cách xử lý sau khi khởi chạy (ví dụ: liệu ứng dụng có nằm trong danh sách hoạt động).Để biết thêm thông tin, hãy xem phương thức
setFlags()
.
Ví dụ về ý định tường minh
Ý định tường minh là ý định mà bạn dùng để chạy một thành phần cụ thể của ứng dụng, chẳng hạn như
hoạt động hoặc dịch vụ cụ thể trong ứng dụng của bạn. Để tạo một ý định tường minh, hãy xác định
tên thành phần cho đối tượng Intent
(tất cả)
các thuộc tính ý định khác (không bắt buộc).
Ví dụ: nếu bạn đã tạo một dịch vụ trong ứng dụng của mình có tên là DownloadService
,
được thiết kế để tải xuống tệp từ web, bạn có thể bắt đầu tệp bằng mã sau:
Kotlin
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" val downloadIntent = Intent(this, DownloadService::class.java).apply { data =Uri.parse
(fileUrl) } startService(downloadIntent)
Java
// Executed in an Activity, so 'this' is theContext
// The fileUrl is a string URL, such as "http://www.example.com/image.png" Intent downloadIntent = new Intent(this, DownloadService.class); downloadIntent.setData(Uri.parse
(fileUrl)); startService(downloadIntent);
Intent(Context, Class)
hàm khởi tạo cung cấp ứng dụng Context
và
thành phần một đối tượng Class
. Do vậy,
ý định này bắt đầu lớp DownloadService
trong ứng dụng một cách rõ ràng.
Để biết thêm thông tin về cách tạo và bắt đầu một dịch vụ, hãy xem Hướng dẫn về Dịch vụ.
Ví dụ về ý định ngầm ẩn
Ý định ngầm ẩn chỉ định một thao tác có thể gọi bất kỳ ứng dụng nào trên thiết bị có khả năng để thực hiện hành động. Việc dùng ý định ngầm ẩn sẽ hữu ích khi ứng dụng của bạn không thể thực hiện hành động mà các ứng dụng khác có thể có và bạn muốn người dùng chọn ứng dụng sẽ sử dụng.
Ví dụ: nếu bạn có nội dung mà bạn muốn người dùng chia sẻ với người khác,
tạo một ý định
bằng thao tác ACTION_SEND
và thêm nội dung bổ sung chỉ định nội dung cần chia sẻ. Khi bạn gọi
startActivity()
với ý định đó, người dùng có thể
chọn một ứng dụng để chia sẻ nội dung.
Kotlin
// Create the text message with a string. val sendIntent = Intent().apply { action = Intent.ACTION_SEND putExtra(Intent.EXTRA_TEXT, textMessage) type = "text/plain" } // Try to invoke the intent. try { startActivity(sendIntent) } catch (e: ActivityNotFoundException) { // Define what your app should do if no activity can handle the intent. }
Java
// Create the text message with a string. Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain"); // Try to invoke the intent. try { startActivity(sendIntent); } catch (ActivityNotFoundException e) { // Define what your app should do if no activity can handle the intent. }
Khi startActivity()
được gọi, hệ thống
kiểm tra tất cả các ứng dụng đã cài đặt để xác định ứng dụng nào có thể xử lý loại ý định này (một
ý định bằng thao tác ACTION_SEND
và có chứa "text/plain"
). Nếu chỉ có một ứng dụng có thể xử lý, ứng dụng đó sẽ mở ngay lập tức và được cấp
ý định. Nếu không có ứng dụng nào khác xử lý được, thì ứng dụng của bạn có thể nắm bắt được
ActivityNotFoundException
xảy ra. Nếu nhiều hoạt động chấp nhận ý định, hệ thống sẽ
hiển thị một hộp thoại như hộp thoại trong Hình 2 để người dùng có thể chọn ứng dụng sẽ dùng.
Thông tin thêm về cách chạy các ứng dụng khác cũng được cung cấp trong hướng dẫn về việc gửi người dùng đến một ứng dụng khác.
![](https://developer.android.google.cn/static/images/training/basics/intent-chooser.png?authuser=9&hl=vi)
Hình 2. Hộp thoại trình chọn.
Buộc một trình chọn ứng dụng
Khi có nhiều ứng dụng phản hồi ý định ngầm ẩn của bạn, người dùng có thể chọn ứng dụng sẽ sử dụng và đặt ứng dụng đó làm lựa chọn mặc định cho hành động. Việc chọn chế độ mặc định sẽ rất hữu ích khi thực hiện một thao tác mà người dùng yêu cầu có thể muốn sử dụng cùng một ứng dụng mọi lúc, chẳng hạn như khi mở một trang web (người dùng thường chỉ thích một trình duyệt web).
Tuy nhiên, nếu nhiều ứng dụng có thể phản hồi ý định và người dùng có thể muốn sử dụng một
mỗi lần, bạn nên hiển thị rõ ràng hộp thoại bộ chọn. Hộp thoại bộ chọn hỏi
người dùng chọn ứng dụng sẽ sử dụng cho hành động (người dùng không thể chọn ứng dụng mặc định cho
hành động). Ví dụ: khi ứng dụng của bạn thực hiện hành động "chia sẻ" thao tác ACTION_SEND
nên người dùng có thể muốn chia sẻ bằng một ứng dụng khác, tuỳ thuộc vào
vào tình hình hiện tại của họ, do đó bạn nên luôn sử dụng hộp thoại bộ chọn, như được minh hoạ trong Hình 2.
Để hiển thị trình chọn, hãy tạo Intent
bằng createChooser()
rồi truyền vào startActivity()
như trong ví dụ sau.
Ví dụ này cho thấy một hộp thoại chứa danh sách các ứng dụng phản hồi ý định được chuyển vào phương thức createChooser()
và dùng văn bản đã cung cấp làm
tiêu đề hộp thoại.
Kotlin
val sendIntent = Intent(Intent.ACTION_SEND) ... // Always use string resources for UI text. // This says something like "Share this photo with" val title: String = resources.getString(R.string.chooser_title) // Create intent to show the chooser dialog val chooser: Intent = Intent.createChooser(sendIntent, title) // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(packageManager) != null) { startActivity(chooser) }
Java
Intent sendIntent = new Intent(Intent.ACTION_SEND); ... // Always use string resources for UI text. // This says something like "Share this photo with" String title = getResources().getString(R.string.chooser_title); // Create intent to show the chooser dialog Intent chooser = Intent.createChooser(sendIntent, title); // Verify the original intent will resolve to at least one activity if (sendIntent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
Phát hiện lượt khởi chạy ý định không an toàn
Ứng dụng của bạn có thể khởi chạy các ý định để di chuyển giữa các thành phần bên trong ứng dụng, hoặc thực hiện hành động thay mặt cho ứng dụng khác. Để cải thiện khả năng bảo mật của nền tảng, Android 12 (API cấp 31) trở lên cung cấp tính năng gỡ lỗi để cảnh báo bạn nếu ứng dụng của bạn khởi chạy một ý định theo cách không an toàn. Ví dụ: ứng dụng của bạn có thể thực hiện việc khởi chạy một ý định lồng nhau một cách không an toàn. Đây là một ý định được truyền làm thông tin bổ sung trong một ý định khác.
Nếu ứng dụng thực hiện cả hai hành động sau đây, thì hệ thống sẽ phát hiện thấy một hành động không an toàn khởi chạy ý định và lỗi vi phạm StrictMode xảy ra:
- Ứng dụng của bạn sẽ tách các ý định lồng nhau khỏi các thành phần đi kèm của ý định đã phân phối.
- Ứng dụng của bạn khởi động ngay một ứng dụng
thành phần bằng cách sử dụng ý định lồng nhau đó,
chẳng hạn như chuyển ý định vào
startActivity()
!startService()
, hoặcbindService()
Để biết thêm thông tin chi tiết về cách xác định trường hợp này và điều chỉnh ứng dụng của bạn, đọc bài đăng trên blog về Android Nesting Ý định trên Medium.
Kiểm tra các lần chạy ý định không an toàn
Để kiểm tra các lần khởi chạy ý định không an toàn trong ứng dụng của bạn, hãy gọi
detectUnsafeIntentLaunch()
khi bạn định cấu hình VmPolicy
, như minh hoạ trong đoạn mã sau. Nếu
ứng dụng của bạn phát hiện lỗi vi phạm StrictMode, nên bạn có thể dừng thực thi ứng dụng để
bảo vệ thông tin có thể nhạy cảm.
Kotlin
fun onCreate() { StrictMode.setVmPolicy(VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()) }
Java
protected void onCreate() { StrictMode.setVmPolicy(new VmPolicy.Builder() // Other StrictMode checks that you've previously added. // ... .detectUnsafeIntentLaunch() .penaltyLog() // Consider also adding penaltyDeath() .build()); }
Sử dụng ý định một cách có trách nhiệm hơn
Để giảm thiểu khả năng khởi chạy ý định không an toàn và vi phạm StrictMode, hãy làm theo các phương pháp hay nhất sau đây.
Chỉ sao chép các thành phần bổ sung thiết yếu trong ý định và thực hiện mọi hoạt động cần thiết
vệ sinh và xác thực. Ứng dụng của bạn có thể sao chép các tiện ích bổ sung từ một ý định sang
một ý định khác dùng để chạy một thành phần mới. Điều này xảy ra khi
cuộc gọi ứng dụng
putExtras(Intent)
hoặc
putExtras(Bundle)
.
Nếu ứng dụng của bạn thực hiện một trong những hoạt động này, chỉ sao chép các dữ liệu bổ sung mà
nhận được kỳ vọng của thành phần. Nếu ý định khác (nhận bản sao)
khởi chạy một thành phần không
xuất, dọn dẹp và
xác thực các dữ liệu bổ sung trước khi sao chép chúng vào ý định khởi chạy
thành phần.
Đừng xuất các thành phần của ứng dụng một cách không cần thiết. Ví dụ: nếu bạn
dự định khởi chạy một thành phần ứng dụng bằng cách sử dụng ý định lồng nhau nội bộ, hãy đặt
thuộc tính android:exported
của thành phần cho false
.
Sử dụng PendingIntent
thay vì
ý định lồng nhau. Nhờ đó, khi một ứng dụng khác tách PendingIntent
của
chứa Intent
, ứng dụng còn lại có thể chạy PendingIntent
bằng cách sử dụng
của ứng dụng. Cấu hình này cho phép ứng dụng kia khởi chạy an toàn
mọi thành phần (kể cả thành phần không xuất) trong ứng dụng của bạn.
Sơ đồ trong hình 2 cho thấy cách hệ thống chuyển quyền kiểm soát từ (máy khách) của bạn ứng dụng sang ứng dụng (dịch vụ) khác và quay lại ứng dụng của bạn:
- Ứng dụng của bạn tạo một ý định gọi hoạt động trong một ứng dụng khác. Bên trong
ý định đó, bạn sẽ thêm một đối tượng
PendingIntent
làm đối tượng bổ sung. Ý định đang chờ xử lý này gọi một thành phần trong ứng dụng của bạn; thành phần này không được xuất. - Sau khi nhận được ý định của ứng dụng, ứng dụng khác sẽ trích xuất các thuộc tính được lồng
Đối tượng
PendingIntent
. - Ứng dụng kia gọi phương thức
send()
trên đối tượngPendingIntent
. - Sau khi chuyển quyền kiểm soát về lại ứng dụng của bạn, hệ thống sẽ gọi lệnh gọi ý định sử dụng ngữ cảnh của ứng dụng.
Hình 2. Sơ đồ giao tiếp trong ứng dụng khi sử dụng cấu hình chờ xử lý lồng nhau ý định.
Nhận được ý định ngầm ẩn
Để quảng cáo những ý định ngầm ẩn mà ứng dụng của bạn có thể nhận được, hãy khai báo một hoặc nhiều bộ lọc ý định cho
mỗi thành phần ứng dụng bằng một <intent-filter>
trong tệp kê khai.
Mỗi bộ lọc ý định chỉ định loại ý định mà bộ lọc đó chấp nhận dựa trên hành động của ý định,
dữ liệu và danh mục. Hệ thống chỉ cung cấp ý định ngầm ẩn cho thành phần ứng dụng nếu
ý định có thể chuyển qua một trong các bộ lọc ý định của bạn.
Lưu ý: Ý định tường minh luôn được phân phối đến mục tiêu, bất kể bộ lọc ý định nào mà thành phần khai báo.
Một thành phần ứng dụng phải khai báo các bộ lọc riêng biệt cho từng công việc riêng biệt mà thành phần đó có thể thực hiện.
Ví dụ: một hoạt động trong ứng dụng thư viện hình ảnh có thể có hai bộ lọc: một bộ lọc
để xem hình ảnh, và dùng một bộ lọc khác để chỉnh sửa hình ảnh. Khi hoạt động bắt đầu,
chương trình này sẽ kiểm tra Intent
và quyết định cách xử lý dựa trên thông tin
trong Intent
(chẳng hạn như để hiện các nút điều khiển của trình chỉnh sửa hay không).
Mỗi bộ lọc ý định do một <intent-filter>
xác định
trong tệp kê khai của ứng dụng, được lồng trong thành phần ứng dụng tương ứng (chẳng hạn như
với tư cách là <activity>
phần tử).
Trong mỗi thành phần ứng dụng có chứa phần tử <intent-filter>
,
Bạn cần đặt giá trị rõ ràng cho
android:exported
.
Thuộc tính này cho biết liệu các ứng dụng khác có thể truy cập vào thành phần ứng dụng hay không. Trong một số
chẳng hạn như các hoạt động có bộ lọc ý định bao gồm
LAUNCHER
danh mục, bạn nên đặt thuộc tính này thành true
. Nếu không,
sẽ an toàn hơn nếu bạn đặt thuộc tính này thành false
.
Cảnh báo: Nếu một hoạt động, dịch vụ hoặc thông báo truyền tin
receiver trong ứng dụng của bạn sử dụng bộ lọc ý định và không đặt giá trị rõ ràng
cho android:exported
, nên bạn không thể cài đặt ứng dụng này trên một thiết bị
chạy Android 12 trở lên.
Bên trong <intent-filter>
,
bạn có thể chỉ định loại ý định cần chấp nhận bằng một hoặc nhiều
trong 3 thành phần này:
<action>
- Khai báo thao tác theo ý định được chấp nhận trong thuộc tính
name
. Giá trị phải là giá trị chuỗi cố định của một hành động, không phải là hằng số lớp. <data>
- Khai báo loại dữ liệu được chấp nhận bằng một hoặc nhiều thuộc tính chỉ định nhiều loại dữ liệu
các khía cạnh của URI dữ liệu (
scheme
,host
,port
,path
) và loại MIME. <category>
- Khai báo danh mục ý định được chấp nhận trong thuộc tính
name
. Giá trị phải là giá trị chuỗi cố định của một tác vụ, không phải là hằng số lớp.Lưu ý: Để nhận ý định ngầm ẩn, bạn phải bao gồm
CATEGORY_DEFAULT
trong bộ lọc ý định. Phương thứcstartActivity()
vàstartActivityForResult()
xử lý mọi ý định như thể chúng đã khai báo danh mụcCATEGORY_DEFAULT
. Nếu bạn không khai báo danh mục này trong bộ lọc ý định, thì sẽ không có ý định ngầm ẩn nào được phân giải hoạt động của bạn.
Ví dụ: dưới đây là nội dung khai báo hoạt động với bộ lọc ý định để nhận
Ý định ACTION_SEND
khi loại dữ liệu là văn bản:
<activity android:name="ShareActivity" android:exported="false"> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> </activity>
Bạn có thể tạo bộ lọc bao gồm nhiều phiên bản của
<action>
!
<data>
hoặc
<category>
.
Nếu làm như vậy, bạn cần chắc chắn rằng thành phần đó có thể xử lý mọi và tất cả
kết hợp các phần tử lọc đó.
Khi bạn muốn xử lý nhiều loại ý định, nhưng chỉ trong các tổ hợp cụ thể của hành động, dữ liệu và loại danh mục, thì bạn cần tạo nhiều bộ lọc ý định.
Ý định ngầm ẩn được kiểm thử so với một bộ lọc bằng cách so sánh ý định đó với mỗi 3 phần tử. Để được phân phối đến thành phần, ý định phải vượt qua cả 3 lượt kiểm thử. Nếu không khớp với bất cứ giá trị nào trong số đó, hệ thống Android sẽ không gửi ý định đến thành phần. Tuy nhiên, vì một thành phần có thể có nhiều bộ lọc ý định, nên một ý định không truyền qua một trong các bộ lọc của thành phần có thể vượt qua được trên một bộ lọc khác. Phần dưới đây cung cấp thêm thông tin về cách hệ thống giải quyết ý định về Giải pháp ý định.
Thận trọng: Sử dụng bộ lọc ý định không phải là cách an toàn để ngăn các ứng dụng khác khởi động
thành phần của bạn. Mặc dù bộ lọc ý định giới hạn một thành phần chỉ phản hồi
một số loại ý định ngầm ẩn nhất định, một ứng dụng khác có thể khởi động thành phần ứng dụng của bạn
bằng cách sử dụng một ý định tường minh nếu nhà phát triển xác định tên thành phần của bạn.
Nếu bạn cần đảm bảo rằng chỉ ứng dụng của riêng bạn mới có thể khởi động một trong các thành phần,
không khai báo bộ lọc ý định trong tệp kê khai. Thay vào đó, hãy đặt
Thuộc tính exported
vào "false"
cho thành phần đó.
Tương tự như vậy, để tránh vô tình chạy một ứng dụng khác
Service
, luôn sử dụng một ý định tường minh để bắt đầu dịch vụ của riêng bạn.
Lưu ý:
Đối với mọi hoạt động, bạn phải khai báo các bộ lọc ý định trong tệp kê khai.
Tuy nhiên, bạn có thể đăng ký bộ lọc cho broadcast receiver một cách linh động bằng cách gọi
registerReceiver()
. Sau đó, bạn có thể huỷ đăng ký trình nhận bằng unregisterReceiver()
. Làm như vậy cho phép ứng dụng của bạn
để nghe các thông báo truyền tin cụ thể chỉ trong một khoảng thời gian nhất định khi ứng dụng của bạn
đang chạy.
Bộ lọc ví dụ
Sau đây là một ví dụ để minh hoạ một số hành vi của bộ lọc ý định từ tệp kê khai của một ứng dụng chia sẻ qua mạng xã hội:
<activity android:name="MainActivity" android:exported="true"> <!-- This activity is the main entry, should appear in app launcher --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ShareActivity" android:exported="false"> <!-- This activity handles "SEND" actions with text data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="text/plain"/> </intent-filter> <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data --> <intent-filter> <action android:name="android.intent.action.SEND"/> <action android:name="android.intent.action.SEND_MULTIPLE"/> <category android:name="android.intent.category.DEFAULT"/> <data android:mimeType="application/vnd.google.panorama360+jpg"/> <data android:mimeType="image/*"/> <data android:mimeType="video/*"/> </intent-filter> </activity>
Hoạt động đầu tiên, MainActivity
, là điểm truy cập chính của ứng dụng – hoạt động mà
mở khi người dùng khởi chạy ứng dụng lần đầu với biểu tượng trình chạy:
- Hành động
ACTION_MAIN
cho biết đây là điểm truy cập chính và không dự kiến có dữ liệu ý định nào. - Danh mục
CATEGORY_LAUNCHER
cho biết hoạt động này biểu tượng nên được đặt trong trình chạy ứng dụng của hệ thống. Nếu phần tử<activity>
không chỉ định biểu tượng bằngicon
, thì hệ thống sẽ sử dụng biểu tượng từ<application>
.
2 URL này phải được ghép nối với nhau để hoạt động xuất hiện trong trình chạy ứng dụng.
Hoạt động thứ hai, ShareActivity
, nhằm hỗ trợ việc chia sẻ văn bản và nội dung nghe nhìn
nội dung. Mặc dù người dùng có thể truy cập vào hoạt động này bằng cách chuyển đến hoạt động đó từ MainActivity
,
họ cũng có thể nhập ShareActivity
trực tiếp từ một ứng dụng khác đưa ra lệnh ngầm ẩn
ý định khớp với một trong hai bộ lọc ý định.
Lưu ý: Loại MIME,
application/vnd.google.panorama360+jpg
là loại dữ liệu đặc biệt chỉ định
ảnh toàn cảnh mà bạn có thể xử lý bằng Google
ảnh toàn cảnh.
So khớp ý định với ý định của các ứng dụng khác bộ lọc ý định
Nếu một ứng dụng khác nhắm đến Android 13 (API cấp 33) trở lên, thì ứng dụng đó có thể xử lý
ý định của ứng dụng chỉ khi ý định của bạn khớp với các hành động và danh mục của
Phần tử <intent-filter>
trong ứng dụng khác đó. Nếu hệ thống không tìm thấy
đối sánh, nó sẽ ném ra một
ActivityNotFoundException
.
Ứng dụng gửi phải xử lý
ngoại lệ này.
Tương tự, nếu bạn cập nhật ứng dụng để nhắm đến Android 13
hoặc cao hơn, tất cả ý định bắt nguồn từ các ứng dụng bên ngoài sẽ được phân phối đến một
thành phần đã xuất của ứng dụng chỉ khi ý định đó khớp với các hành động và
danh mục của phần tử <intent-filter>
mà ứng dụng của bạn khai báo. Hành vi này
xảy ra bất kể phiên bản SDK mục tiêu của ứng dụng gửi.
Trong các trường hợp sau đây, tính năng so khớp ý định sẽ không được thực thi:
- Ý định được phân phối đến các thành phần không khai báo bộ lọc ý định nào.
- Các ý định bắt nguồn từ trong cùng một ứng dụng.
- Ý định bắt nguồn từ hệ thống; tức là ý định được gửi từ
"UID hệ thống" (uid=1000). Các ứng dụng hệ thống bao gồm
system_server
và những ứng dụng đặtandroid:sharedUserId
đếnandroid.uid.system
. - Ý định bắt nguồn từ gốc.
Tìm hiểu thêm về tính năng so khớp ý định.
Sử dụng ý định đang chờ xử lý
Đối tượng PendingIntent
là một trình bao bọc xung quanh đối tượng Intent
. Mục đích chính của PendingIntent
là cấp quyền cho một đơn đăng ký nước ngoài
để sử dụng Intent
chứa trong đó như thể nó được thực thi từ
của riêng ứng dụng.
Sau đây là các trường hợp sử dụng chính của một ý định đang chờ xử lý:
- Khai báo ý định sẽ được thực thi khi người dùng thực hiện một hành động thông qua Thông báo của bạn
(
NotificationManager
của hệ thống Android thực thiIntent
). - Khai báo ý định sẽ được thực thi khi người dùng thực hiện một thao tác bằng
Tiện ích ứng dụng
(ứng dụng Màn hình chính thực thi
Intent
). - Khai báo ý định sẽ được thực thi vào một thời điểm cụ thể trong tương lai (Android
AlarmManager
của hệ thống thực thiIntent
).
Giống như việc mỗi đối tượng Intent
được thiết kế để do một đối tượng cụ thể
loại thành phần ứng dụng (Activity
, Service
hoặc
BroadcastReceiver
), do đó, PendingIntent
cũng phải là
được tạo với cùng một mức độ cân nhắc. Khi sử dụng một ý định đang chờ xử lý, ứng dụng của bạn sẽ không
thực thi ý định bằng một lệnh gọi như startActivity()
. Thay vào đó, bạn phải khai báo loại thành phần dự định khi tạo
PendingIntent
bằng cách gọi phương thức tương ứng của trình tạo:
PendingIntent.getActivity()
cho mộtIntent
bắt đầu mộtActivity
.PendingIntent.getService()
cho mộtIntent
bắt đầu mộtService
.PendingIntent.getBroadcast()
cho mộtIntent
bắt đầu mộtBroadcastReceiver
.
Trừ phi ứng dụng của bạn nhận được ý định đang chờ xử lý từ các ứng dụng khác,
các phương thức trên để tạo PendingIntent
có lẽ là phương pháp duy nhất
Các phương thức PendingIntent
mà bạn cần.
Mỗi phương thức sẽ lấy ứng dụng hiện tại Context
,
Intent
mà bạn muốn gói và một hoặc nhiều cờ chỉ định
cách sử dụng ý định (chẳng hạn như liệu ý định có thể được sử dụng nhiều lần hay không).
Để biết thêm thông tin về cách sử dụng ý định đang chờ xử lý, hãy xem tài liệu về từng ý định của các trường hợp sử dụng tương ứng, chẳng hạn như trong phần Thông báo và hướng dẫn về API Tiện ích ứng dụng.
Chỉ định khả năng biến đổi
Nếu ứng dụng của bạn nhắm đến Android 12 trở lên, bạn phải chỉ định
khả năng biến đổi của từng đối tượng PendingIntent
mà ứng dụng của bạn tạo ra. Để khai báo rằng
một đối tượng PendingIntent
nhất định có thể thay đổi hoặc không thể thay đổi, hãy sử dụng phương thức
PendingIntent.FLAG_MUTABLE
hoặc
PendingIntent.FLAG_IMMUTABLE
cờ hiệu.
Nếu ứng dụng của bạn cố gắng tạo một đối tượng PendingIntent
nếu bạn không đặt cờ về khả năng biến đổi, hệ thống sẽ gửi
IllegalArgumentException
và
thông báo sau sẽ xuất hiện trong Logcat:
PACKAGE_NAME: Targeting S+ (version 31 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.
Tạo ý định đang chờ xử lý bất biến bất cứ khi nào có thể
Trong hầu hết các trường hợp, ứng dụng của bạn phải tạo các đối tượng PendingIntent
bất biến, vì
được hiển thị trong đoạn mã sau. Nếu một đối tượng PendingIntent
là không thể thay đổi,
thì các ứng dụng khác không thể sửa đổi ý định để điều chỉnh kết quả của việc gọi
ý định.
Kotlin
val pendingIntent = PendingIntent.getActivity(applicationContext, REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), REQUEST_CODE, intent, /* flags */ PendingIntent.FLAG_IMMUTABLE);
Tuy nhiên, một số trường hợp sử dụng nhất định yêu cầu các đối tượng PendingIntent
có thể thay đổi:
- Hỗ trợ thao tác trả lời trực tiếp trong
thông báo. Chiến lược phát hành đĩa đơn
câu trả lời trực tiếp yêu cầu thay đổi dữ liệu đoạn video trong đối tượng PendingIntent
liên quan đến câu trả lời. Thông thường, bạn yêu cầu thay đổi này bằng cách chuyển
FILL_IN_CLIP_DATA
làm cờ chofillIn()
. - Liên kết thông báo với khung Android Auto, sử dụng các thực thể của
CarAppExtender
. - Đặt cuộc trò chuyện trong bong bóng trò chuyện bằng thực thể
trong tổng số
PendingIntent
. Đối tượngPendingIntent
có thể thay đổi cho phép hệ thống áp dụng cờ chính xác, chẳng hạn nhưFLAG_ACTIVITY_MULTIPLE_TASK
vàFLAG_ACTIVITY_NEW_DOCUMENT
. - Yêu cầu thông tin vị trí thiết bị bằng cách gọi
requestLocationUpdates()
hoặc các API tương tự. Đối tượngPendingIntent
có thể thay đổi cho phép hệ thống thêm ý định bổ sung đại diện cho các sự kiện trong vòng đời của vị trí. Những sự kiện này bao gồm thay đổi về địa điểm và nhà cung cấp sẽ xuất hiện. - Lên lịch chuông báo bằng
AlarmManager
. Đối tượngPendingIntent
có thể thay đổi cho phép hệ thống thêmEXTRA_ALARM_COUNT
ý định bổ sung. Phần phụ này thể hiện số lần một chuông báo lặp lại đã được kích hoạt. Bằng cách chứa phần bổ sung này, ý định có thể thông báo chính xác một ứng dụng liên quan đến việc một chuông báo lặp lại có được kích hoạt nhiều lần hay không, chẳng hạn như khi thiết bị ở chế độ ngủ.
Nếu ứng dụng của bạn tạo đối tượng PendingIntent
có thể thay đổi, bạn nên
mà bạn sử dụng một ý định tường minh và điền vào
ComponentName
. Bằng cách đó, bất cứ khi nào
một ứng dụng khác gọi PendingIntent
và chuyển quyền kiểm soát về lại ứng dụng của bạn,
cùng một thành phần trong ứng dụng của bạn luôn khởi động.
Sử dụng ý định tường minh trong ý định đang chờ xử lý
Để xác định rõ hơn cách các ứng dụng khác có thể dùng ý định đang chờ xử lý của ứng dụng, hãy luôn luôn gói ý định đang chờ xử lý xung quanh một ý định tường minh. Để làm theo phương pháp hay nhất này, hãy làm như sau:
- Kiểm tra để đảm bảo các trường hành động, gói và thành phần của ý định cơ sở .
-
Sử dụng
FLAG_IMMUTABLE
, thêm vào Android 6.0 (API cấp 23) để tạo ý định đang chờ xử lý. Cờ này ngăn các ứng dụng nhận đượcPendingIntent
điền vào các cơ sở lưu trú không được điền sẵn. NếuminSdkVersion
của ứng dụng là22
trở xuống, bạn có thể cung cấp sự an toàn và khả năng tương thích cùng nhau bằng mã sau:if (Build.VERSION.SDK_INT >= 23) { // Create a PendingIntent using FLAG_IMMUTABLE. } else { // Existing code that creates a PendingIntent. }
Phân giải ý định
Khi nhận được ý định ngầm ẩn để bắt đầu một hoạt động, hệ thống sẽ tìm kiếm hoạt động hiệu quả nhất cho ý định đó bằng cách so sánh ý định đó với các bộ lọc ý định dựa trên 3 khía cạnh:
- Quay!
- Dữ liệu (cả URI và loại dữ liệu).
- Danh mục.
Các phần sau đây mô tả cách so khớp ý định với các thành phần thích hợp theo nội dung khai báo bộ lọc ý định trong tệp kê khai của ứng dụng.
Thử nghiệm hành động
Để chỉ định các thao tác theo ý định được chấp nhận, bộ lọc ý định có thể khai báo số 0 hoặc nhiều hơn
Phần tử <action>
, như trong ví dụ sau:
<intent-filter> <action android:name="android.intent.action.EDIT" /> <action android:name="android.intent.action.VIEW" /> ... </intent-filter>
Để vượt qua bộ lọc này, hành động được chỉ định trong Intent
phải phù hợp với một trong các hành động được liệt kê trong bộ lọc.
Nếu bộ lọc không liệt kê hành động nào thì sẽ không có hành động nào
ý định khớp, vì vậy tất cả ý định đều không vượt qua kiểm thử. Tuy nhiên, nếu một Intent
không chỉ định hành động, mà vượt qua thử nghiệm miễn là bộ lọc
chứa ít nhất một hành động.
Thử nghiệm danh mục
Để chỉ định các danh mục ý định được chấp nhận, bộ lọc ý định có thể khai báo số không hoặc nhiều mục đích khác
Phần tử <category>
, như trong ví dụ sau:
<intent-filter> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> ... </intent-filter>
Để có thể vượt qua bài kiểm thử danh mục, mọi danh mục trong Intent
phải khớp với một danh mục trong bộ lọc. Ngược lại là không cần thiết – bộ lọc ý định có thể
khai báo nhiều danh mục hơn danh mục được chỉ định trong Intent
và
Intent
vẫn vượt qua. Do đó, một ý định không có danh mục nào
luôn vượt qua kiểm tra này, bất kể danh mục nào được khai báo trong bộ lọc.
Lưu ý:
Android tự động áp dụng danh mục CATEGORY_DEFAULT
cho tất cả các ý định ngầm ẩn được truyền đến startActivity()
và startActivityForResult()
.
Nếu bạn muốn hoạt động của mình nhận được ý định ngầm ẩn, thì hoạt động đó phải
bao gồm một danh mục cho "android.intent.category.DEFAULT"
trong các bộ lọc ý định, như
như trong ví dụ trước về <intent-filter>
.
Kiểm tra dữ liệu
Để chỉ định dữ liệu ý định được chấp nhận, bộ lọc ý định có thể khai báo số không hoặc nhiều hơn
Phần tử <data>
, như trong ví dụ sau:
<intent-filter> <data android:mimeType="video/mpeg" android:scheme="http" ... /> <data android:mimeType="audio/mpeg" android:scheme="http" ... /> ... </intent-filter>
Mỗi <data>
có thể chỉ định cấu trúc URI và kiểu dữ liệu (kiểu đa phương tiện MIME).
Mỗi phần của URI là một phần riêng biệt
thuộc tính: scheme
, host
, port
,
và path
:
<scheme>://<host>:<port>/<path>
Ví dụ sau đây trình bày các giá trị có thể có cho các thuộc tính này:
content://com.example.project:200/folder/subfolder/etc
Trong URI này, giao thức là content
, máy chủ lưu trữ là com.example.project
,
cổng là 200
và đường dẫn là folder/subfolder/etc
.
Mỗi thuộc tính trong số này là không bắt buộc trong phần tử <data>
,
nhưng có các phần phụ thuộc tuyến tính:
- Nếu không chỉ định giao thức thì máy chủ sẽ bị bỏ qua.
- Nếu máy chủ không được chỉ định, cổng sẽ bị bỏ qua.
- Nếu cả giao thức và máy chủ lưu trữ không được chỉ định, thì đường dẫn sẽ bị bỏ qua.
Khi so sánh URI trong một ý định với thông số kỹ thuật của URI trong một bộ lọc, dữ liệu đó chỉ được so sánh với các phần của URI có trong bộ lọc. Ví dụ:
- Nếu một bộ lọc chỉ chỉ định một lược đồ, thì tất cả các URI có lược đồ đó đều khớp bộ lọc.
- Nếu một bộ lọc chỉ định một giao thức và một thẩm quyền nhưng không có đường dẫn, thì tất cả URI có cùng giao thức và thẩm quyền sẽ vượt qua bộ lọc, bất kể đường dẫn của chúng.
- Nếu bộ lọc chỉ định một giao thức, một thẩm quyền và một đường dẫn, thì chỉ các URI có cùng giao thức đó, đơn vị tổ chức và đường dẫn chuyển qua bộ lọc.
Lưu ý: Quy cách đường dẫn có thể chứa dấu hoa thị ký tự đại diện (*) để chỉ yêu cầu kết quả khớp một phần của tên đường dẫn.
Hoạt động kiểm thử dữ liệu so sánh cả URI và loại MIME trong ý định với một URI và loại MIME đã chỉ định trong bộ lọc. Các quy tắc này như sau:
- Một ý định không chứa URI và loại MIME nào chỉ kiểm tra nếu bộ lọc không chỉ định bất kỳ loại URI hoặc MIME nào.
- Một ý định có chứa URI nhưng không có loại MIME (không rõ ràng cũng không suy luận được từ URI) chỉ vượt qua quy trình kiểm thử nếu URI của URI đó khớp với định dạng URI của bộ lọc và bộ lọc cũng không chỉ định loại MIME.
- Một ý định chứa loại MIME nhưng không phải URI có vượt qua bài kiểm thử chỉ khi bộ lọc liệt kê cùng một loại MIME và không chỉ định định dạng URI.
- Một ý định chứa cả URI và loại MIME (tức là tường minh hoặc có thể suy ra từ
URI) chỉ vượt qua phần loại MIME của kiểm thử nếu điều đó
khớp với một loại được liệt kê trong bộ lọc. Tham số này vượt qua phần URI của hoạt động kiểm thử
hoặc nếu URI của URL đó khớp với URI trong bộ lọc hoặc có
content:
hoặc URIfile:
và bộ lọc không chỉ định URI. Nói cách khác, một thành phần được cho là hỗ trợ dữ liệucontent:
vàfile:
nếu bộ lọc của bộ lọc chỉ liệt kê loại MIME.
Lưu ý: Nếu một ý định chỉ định loại URI hoặc MIME, thì quá trình kiểm thử dữ liệu sẽ
không thành công nếu không có phần tử <data>
trong <intent-filter>
.
Quy tắc cuối cùng này, quy tắc (d), phản ánh kỳ vọng
mà các thành phần có thể nhận dữ liệu cục bộ từ tệp hoặc trình cung cấp nội dung.
Do đó, các bộ lọc của họ chỉ có thể liệt kê một loại dữ liệu và không cần phải thể hiện rõ ràng
đặt tên cho giao thức content:
và file:
.
Ví dụ sau đây cho thấy một trường hợp điển hình, trong đó phần tử <data>
cho Android biết rằng thành phần này có thể lấy dữ liệu hình ảnh qua một nội dung
và hiển thị nhà cung cấp dịch vụ đó:
<intent-filter> <data android:mimeType="image/*" /> ... </intent-filter>
Các bộ lọc chỉ định loại dữ liệu nhưng không phải URI có lẽ là loại dữ liệu phổ biến nhất dữ liệu do các nhà cung cấp nội dung phân phối.
Một cấu hình phổ biến khác là bộ lọc có lược đồ và kiểu dữ liệu. Cho
Ví dụ: <data>
như phần tử sau cho Android biết rằng
thành phần có thể truy xuất dữ liệu video từ mạng để thực hiện hành động:
<intent-filter> <data android:scheme="http" android:mimeType="video/*" /> ... </intent-filter>
So khớp ý định
Ý định được so khớp với bộ lọc ý định không chỉ để khám phá một mục tiêu
thành phần cụ thể để kích hoạt, mà còn để khám phá điều gì đó về tập hợp
các thành phần trên thiết bị. Ví dụ: ứng dụng Home điền sẵn trình chạy ứng dụng
bằng cách tìm tất cả các hoạt động có bộ lọc ý định chỉ định
ACTION_MAIN
hành động và
Danh mục CATEGORY_LAUNCHER
.
Kết quả so khớp chỉ thành công nếu các hành động và danh mục trong Ý định khớp
dựa vào bộ lọc, như được mô tả trong tài liệu về IntentFilter
.
Ứng dụng của bạn có thể sử dụng tính năng so khớp ý định theo cách tương tự như ứng dụng Home.
PackageManager
có một tập hợp query...()
phương thức trả về tất cả các thành phần có thể chấp nhận một ý định cụ thể và
một loạt phương thức resolve...()
tương tự giúp xác định phương pháp hiệu quả nhất
để phản hồi một ý định. Ví dụ:
queryIntentActivities()
trả về danh sách tất cả hoạt động có thể thực hiện
ý định được truyền dưới dạng đối số và queryIntentServices()
trả về một danh sách dịch vụ tương tự.
Không có phương thức nào kích hoạt các thành phần; họ chỉ liệt kê những gì
có thể phản hồi. Có một phương pháp tương tự,
queryBroadcastReceivers()
, đối với broadcast receiver.