Android 應用程式可利用 Kotlin、Java 程式設計語言和 C 語言編寫。Android SDK 工具會將您的程式碼以及任何資料和資源檔案編譯成 APK 或 Android App Bundle。
Android 套件是具有 .apk
後置字串的封存檔案,包含執行階段需要的 Android 應用程式內容,也是 Android 裝置用來安裝應用程式的檔案。
Android App Bundle 是具有 .aab
後置字串的封存檔案,內含 Android 應用程式專案的內容,包括執行階段不需要的額外中繼資料。AAB 是發布格式,無法安裝在 Android 裝置上。這會延遲 APK 產生及簽署之後的階段。
舉例來說,當您透過 Google Play 發行應用程式時,Google Play 的伺服器會產生最佳化 APK,其中僅包含要求安裝應用程式的特定裝置所需的資源和程式碼。
每個 Android 應用程式都位於各自的安全沙箱中,並受到下列 Android 安全性功能保護:
- Android 作業系統是多使用者的 Linux 系統,其中每個應用程式都屬於不同使用者。
- 根據預設,系統會為每個應用程式指派專屬的 Linux 使用者 ID;該 ID 僅由系統使用且應用程式無法辨識。系統會設定應用程式中所有檔案的權限,只讓指派給該應用程式的使用者 ID 才能存取。
- 每個程序都有自己的虛擬機器 (VM),因此應用程式的程式碼獨立於其他應用程式之外執行。
- 根據預設,每個應用程式都是在各自的 Linux 程序中執行。Android 系統會在需要執行應用程式的任何元件時啟動該程序,然後在不再需要該程序或系統必須復原其他應用程式的記憶體時,關閉該程序。
Android 系統採用最低權限原則。也就是說,每個應用程式預設都只能存取執行其所需的元件。這麼做可建立非常安全的環境,讓應用程式無法存取未獲得權限的系統部分。
不過,應用程式可透過下列幾種方式與其他應用程式共用資料,以及讓應用程式存取系統服務的方法:
- 您可以安排兩個應用程式共用相同的 Linux 使用者 ID,這樣他們就能存取彼此的檔案。如要節省系統資源,具有相同使用者 ID 的應用程式也能安排在相同的 Linux 程序中執行,並共用相同的 VM。應用程式也必須使用相同的憑證簽署。
- 應用程式可以要求存取裝置資料的權限,例如裝置的位置、相機和藍牙連線。使用者必須明確授予這些權限。如要進一步瞭解權限,請參閱「Android 中的權限」。
本文件其他部分介紹了以下概念:
- 定義應用程式的核心架構元件。
- 用於宣告應用程式元件和必要裝置功能的資訊清單檔案。
- 這類資源與應用程式程式碼不同,可讓應用程式針對各種裝置設定順利最佳化行為。
應用程式元件
應用程式元件是 Android 應用程式的重要構成要素。每個元件都是系統或使用者可以進入應用程式的進入點。部分元件取決於其他元件。
應用程式元件分為四種類型:
- 活動
- 服務
- 廣播接收器
- 內容供應器
每種類型各有其用途,且具有不同的生命週期,定義元件的建立和刪除方式。以下各節說明應用程式元件的四種類型。
- 活動
- 「活動」是與使用者互動的進入點。這代表包含使用者介面的單一畫面。舉例來說,電子郵件應用程式可能有一項活動顯示新電子郵件的清單、另一個用來撰寫電子郵件的活動,以及另一個用於讀取電子郵件的活動。雖然這些活動會搭配運作,藉此在電子郵件應用程式中打造一致的使用者體驗,但兩者各自獨立。
如果電子郵件應用程式允許,其他應用程式可以啟動上述任一活動。舉例來說,相機應用程式可在電子郵件應用程式中啟動活動,用來撰寫新的電子郵件,讓使用者分享相片。
活動有利於系統和應用程式之間進行下列主要互動:
- 持續追蹤使用者關注的內容 (螢幕上的內容),以便系統繼續執行代管活動的程序。
- 瞭解哪些程序含有先前使用的程序,且使用者可能會再次使用,並更優先這些程序來保持可用。
- 協助應用程式處理終止程序,讓使用者可以返回還原先前的狀態活動。
- 為應用程式提供一種方法,讓應用程式彼此之間導入使用者流程,以及讓系統協調這些流程。其中最主要的例子是分享。
- 服務
- 「服務」是基於各種原因而確保應用程式在背景執行的一般用途進入點。它是一個元件,會在背景執行長時間執行的作業或執行遠端程序的工作。服務不提供使用者介面。
舉例來說,當使用者位於其他應用程式時,服務可能會在背景播放音樂,或者在不封鎖使用者與活動之間互動的情況下,透過網路擷取資料。另一個元件 (例如活動) 可以啟動服務,並使其執行或繫結至服務與其互動。
有兩種服務會指示系統如何管理應用程式:已啟動的服務和繫結的服務。
已啟動的服務會指示系統在作業完成前繼續執行這些服務。這可能會在使用者離開應用程式後,於背景同步處理部分資料或播放音樂。在背景中同步處理資料或播放音樂代表不同類型的啟動服務,以不同方式處理:
- 音樂播放是使用者直接察覺的事項,而應用程式會透過通知在前景執行,並通知使用者該程式正在執行中,藉此向系統傳達此訊息。在這種情況下,系統會優先確保服務程序持續執行,因為一旦使用者關閉,就會有不愉快的體驗。
- 一般背景服務無法讓使用者直接察覺,因此系統有利於管理其程序。以免系統終止服務,並在日後需要使用 RAM 來處理對使用者較為直接的事務。
繫結服務會執行,因為一些其他應用程式 (或系統) 表示想要使用該服務。繫結服務會提供 API 給其他程序,而系統知道這些程序之間有依附元件。因此,如果程序 A 繫結至程序 B 中的服務,系統會知道必須讓程序 B 和服務繼續執行 A 程序。此外,如果程序 A 是使用者重視的事,他們知道要將 B 程序 B 視為使用者也在乎的事情。
由於服務具有彈性,因此對於各種較高階的系統概念而言,服務都是實用的建構區塊。動態桌布、通知監聽器、螢幕保護程式、輸入法、無障礙服務和許多其他核心系統功能都是以應用程式實作的形式建構,並在執行時由系統繫結。
服務會實作為
Service
的子類別。如要進一步瞭解Service
類別,請參閱「 服務總覽」。注意:如果應用程式指定的是 Android 5.0 (API 級別 21) 以上版本,請使用
JobScheduler
類別安排動作。JobScheduler 可透過最佳方式排定工作來降低耗電量,並利用 Doze API 來節省電力。如要進一步瞭解如何使用這個類別,請參閱JobScheduler
參考說明文件。 - 廣播接收器
- 「廣播接收器」是一種元件,可讓系統在一般使用者流程之外將事件傳送至應用程式,以便應用程式回應整個系統的廣播公告。由於廣播接收器是在應用程式中另一個明確定義的項目,因此即使是目前並未執行的應用程式,系統也能提供廣播訊息。
舉例來說,應用程式可以排定鬧鐘發布通知,告知使用者即將到來的活動。由於鬧鐘已傳送至應用程式中的
BroadcastReceiver
,因此在鬧鐘響起之前,應用程式不需要保持運作。許多廣播來自系統的廣播,例如廣播宣布螢幕已關閉、電量不足或擷取相片。應用程式也可以啟動廣播訊息,例如通知其他應用程式已下載部分資料至裝置中且可供使用。
雖然廣播接收器不會顯示使用者介面,但可以建立狀態列通知,在廣播事件發生時通知使用者。更常見的做法是,廣播接收器是其他元件的「閘道」,用途是執行最少工作。
舉例來說,廣播接收器可能會排定
JobService
,根據使用JobScheduler
的事件執行某些工作。廣播接收器通常會涉及應用程式彼此互動,因此設定時務必瞭解可能造成的影響。廣播接收器會以
BroadcastReceiver
的子類別實作,而每個廣播都會以Intent
物件的形式傳遞。詳情請參閱BroadcastReceiver
類別。 - 內容供應器
- 內容供應器管理一組共用的應用程式資料,您可以儲存在檔案系統、SQLite 資料庫、網路上,或任何應用程式可存取的任何其他永久儲存空間位置。透過內容供應器,其他應用程式可以查詢或修改資料 (如果內容供應器允許)。
舉例來說,Android 系統提供了可管理使用者聯絡資訊的內容供應器。任何具備適當權限的應用程式都可以查詢內容供應器 (例如使用
ContactsContract.Data
),讀取及寫入特定使用者的相關資訊。慢慢將內容供應器視為資料庫上的抽象層,因為有很多 API 並內建支援,針對這個常見情況。但從系統設計的角度來看,其核心用途不同。
對系統而言,內容供應器是應用程式中的進入點,用於發布透過 URI 配置識別的具名資料項目。因此,應用程式可以決定其包含的資料要如何對應至 URI 命名空間,然後將這些 URI 分發給其他實體,並利用這些 URI 存取資料。如此一來,系統在管理應用程式時,就能派上用場:
- 指派 URI 時,應用程式不必繼續執行,因此 URI 可以在自身的應用程式結束結束後繼續保留。系統從對應的 URI 擷取應用程式資料時,只需要確保自有應用程式仍在執行。
- 這些 URI 也提供重要的精細安全性模型。舉例來說,應用程式可以把本身所含圖片的 URI 放在剪貼簿中,但讓內容供應器保持鎖定,導致其他應用程式無法自由存取該圖片。第二個應用程式嘗試存取剪貼簿上的該 URI 時,系統會允許該應用程式使用臨時的 URI 權限授權存取資料,以便其僅存取該 URI 背後的資料,不會在第二個應用程式中存取任何其他內容。
內容供應器也適合用於讀取及寫入只有應用程式而未共用的資料。
內容供應器會實作為
ContentProvider
的子類別,且必須實作一組標準 API,讓其他應用程式可以執行交易。詳情請參閱「內容供應器」開發人員指南。
Android 系統設計的其中一個獨特之處是任何應用程式都可以啟動其他應用程式的元件。舉例來說,如果您希望使用者使用裝置相機拍照,可能有其他的應用程式可以這樣做,您的應用程式可以使用該應用程式,不必開發活動自行拍照。不需要加入或甚至連結到相機應用程式的程式碼。請改為在相機應用程式中啟動活動,擷取相片。上傳完成後,相片也會傳回給應用程式,讓您可以正常使用。對使用者而言,相機似乎是應用程式的一部分。
當系統啟動元件時,如果應用程式尚未執行,便會啟動該應用程式的程序,並將元件所需的類別執行個體化。舉例來說,如果應用程式在相機應用程式中啟動活動,該活動會在相機應用程式 (而不是應用程式的程序) 中執行。因此,與大多數系統上的應用程式不同,Android 應用程式不會有一個單一進入點,因為沒有 main()
函式。
由於系統會獨立執行每個應用程式,且檔案權限會限制其他應用程式的存取權,因此應用程式無法直接從其他應用程式啟動元件。不過,Android 系統可以。如要在其他應用程式中啟用元件,您需要向系統傳送訊息,指定您要啟動特定元件的意圖。接著,系統會為您啟用元件。
啟用元件
名為「意圖」的非同步訊息會啟動四種元件類型中的三種:活動、服務和廣播接收器。意圖會在執行階段將個別元件繫結在一起。您可以將其視為要求其他元件執行操作的訊息 (無論元件屬於您的應用程式或其他元件)。
意圖是透過 Intent
物件建立,該物件會定義要啟用特定元件 (「明確」意圖) 或特定類型元件 (「隱含」意圖) 的訊息。
如果是活動和服務,意圖會定義要執行的動作,例如「查看」或「傳送」,也可能指定要採取行動的資料 URI 以及啟動元件可能需要瞭解的其他內容。
舉例來說,意圖可能會傳送顯示圖片或開啟網頁的活動要求。在某些情況下,您可以啟動活動來接收結果,在這種情況下,活動也會在 Intent
中傳回結果。您也可以發出意圖,讓使用者挑選個人聯絡人並退回給您。傳回意圖會包含指向所選聯絡人的 URI。
針對廣播接收器,意圖會定義廣播公告。例如,廣播表示裝置電量偏低的廣播僅包含表示「電池電力不足」的已知動作字串。
與活動、服務和廣播接收器不同,內容供應器會在 ContentResolver
的要求指定時啟用。內容解析器會處理內容供應器的所有直接交易,元件則會在 ContentResolver
物件上透過供應器呼叫方法執行交易。這會在內容供應器與要求資訊的元件之間保留一層抽象層,以確保安全性。
啟用每種元件類型各有不同的方法:
- 您可以將
Intent
傳送至startActivity()
,或是希望活動傳回結果時 (startActivityForResult()
) 來啟動活動或進行新活動。 - 在 Android 5.0 (API 級別 21) 以上版本中,您可以使用
JobScheduler
類別排定動作。若是較舊版本的 Android,您可以傳遞Intent
至startService()
,以便啟動服務或為持續中的服務提供新操作說明。只要將Intent
傳遞至bindService()
,即可繫結至服務。 - 如要啟動廣播,請將
Intent
傳遞至sendBroadcast()
或sendOrderedBroadcast()
等方法。 - 您可以對
ContentResolver
呼叫query()
,藉此對內容供應器執行查詢。
如要進一步瞭解如何使用意圖,請參閱「意圖和意圖篩選器」文件。下列文件提供啟用特定元件的詳細資訊:活動簡介、服務總覽、BroadcastReceiver
和內容供應器。
資訊清單檔案
在 Android 系統啟動應用程式元件之前,系統必須藉由讀取應用程式的資訊清單檔案 AndroidManifest.xml
來知道元件確實存在。應用程式會宣告這個檔案中的所有元件,該檔案位於應用程式專案目錄的根目錄。
資訊清單除了宣告應用程式元件之外,還需要執行其他作業,例如:
- 找出應用程式需要的任何使用者權限,例如網際網路存取權或使用者聯絡人的讀取權限。
- 根據應用程式使用的 API,宣告應用程式所需的最低 API 級別。
- 宣告應用程式使用或需要的硬體和軟體功能,例如相機、藍牙服務或多點觸控螢幕。
- 宣告應用程式需要建立連結的 API 程式庫 (Android 架構 API 除外),例如 Google 地圖程式庫。
宣告元件
資訊清單的主要工作是告知系統應用程式的元件。例如,資訊清單檔案可以宣告活動,如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest ... > <application android:icon="@drawable/app_icon.png" ... > <activity android:name="com.example.project.ExampleActivity" android:label="@string/example_label" ... > </activity> ... </application> </manifest>
在 <application>
元素中,android:icon
屬性會指向可識別應用程式圖示的資源。
在 <activity>
元素中,android:name
屬性會指定 Activity
子類別的完整類別名稱,android:label
屬性會指定做為活動使用者可見標籤的字串。
您必須使用下列元素宣告所有應用程式元件:
- 活動的
<activity>
元素 - 服務的
<service>
元素 - 廣播接收器的
<receiver>
元素 - 內容供應器的
<provider>
元素
您在來源中加入但未在資訊清單中宣告的活動、服務和內容供應器不會向系統顯示,因此也一律無法執行。不過,廣播接收器可以在資訊清單中宣告,也可以在程式碼中以 BroadcastReceiver
物件動態建立,並藉由呼叫 registerReceiver()
向系統註冊。
如要進一步瞭解如何建構應用程式的資訊清單檔案,請參閱「應用程式資訊清單總覽」。
宣告元件功能
如「啟用元件」一節所述,您可以使用 Intent
啟動活動、服務和廣播接收器。方法是在意圖中使用元件類別名稱明確命名目標元件。您也可以使用隱含意圖來說明要執行的動作類型,以及指定要用於執行動作的資料。隱含意圖可讓系統在裝置上尋找可執行動作的元件,然後啟動該動作。如果多個元件可執行意圖描述的動作,使用者會選取要使用的元件。
注意:如果您使用意圖啟動 Service
,請使用明確意圖,確保應用程式安全無虞。使用隱含意圖啟動服務會造成安全性危害,因為您無法確定哪一項服務回應意圖,又使用者也看不到啟動的服務。從 Android 5.0 (API 級別 21) 開始,如果您使用隱含意圖呼叫 bindService()
,系統會擲回例外狀況。請勿為服務宣告意圖篩選器。
系統會比較收到的意圖與裝置上其他應用程式資訊清單檔案提供的意圖篩選器,藉此找出可回應意圖的元件。
在應用程式資訊清單中宣告活動時,您可以選擇加入意圖篩選器來宣告活動功能,以便回應其他應用程式的意圖。方法是將 <intent-filter>
元素新增為元件宣告元素的子項。
舉例來說,如果您建構的電子郵件應用程式含有撰寫新電子郵件的活動,您可以宣告意圖篩選器來回應「傳送」意圖來傳送新電子郵件,如以下範例所示:
<manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
如果其他應用程式使用 ACTION_SEND
動作建立意圖並傳遞至 startActivity()
,系統可能會啟動您的活動,讓使用者能編寫草稿並傳送電子郵件。
如要進一步瞭解如何建立意圖篩選器,請參閱「意圖和意圖篩選器」文件。
聲明應用程式規定
市面上有許多搭載 Android 系統的裝置,但並非所有裝置都提供相同的功能。為避免在缺少應用程式所需功能的裝置上安裝應用程式,請務必在資訊清單檔案中宣告裝置和軟體需求,藉此針對應用程式支援的裝置類型明確定義設定檔。
這些聲明大多僅供參考,系統不會讀取這些憑證,但 Google Play 等外部服務會讀取這些服務,以便在使用者透過裝置搜尋應用程式時提供篩選功能。
舉例來說,假設您的應用程式需要相機,並使用 Android 8.0 (API 級別 26) 中引入的 API。您必須宣告這些規定。minSdkVersion
和 targetSdkVersion
的值可在應用程式模組的 build.gradle
檔案中設定:
android { ... defaultConfig { ... minSdkVersion 26 targetSdkVersion 29 } }
注意:請勿直接在資訊清單檔案中設定 minSdkVersion
和 targetSdkVersion
,因為在建構過程中,Gradle 會覆寫這些項目。詳情請參閱「指定 API 級別規定」。
在應用程式的資訊清單檔案中宣告相機功能:
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> ... </manifest>
上述範例顯示的宣告後,如果裝置「沒有」相機,或 Android 版本「低於」8.0,就無法透過 Google Play 安裝應用程式。不過,您也可以宣告應用程式使用相機,但並非必要。方法是將 required
屬性設為 false
,在執行階段檢查裝置是否有相機,並視需要停用任何相機功能。
如要進一步瞭解如何管理應用程式與不同裝置的相容性,請參閱「裝置相容性總覽」。
應用程式資源
Android 應用程式不只由程式碼組成,必須使用與原始碼不同的資源,例如圖片、音訊檔案,以及與應用程式視覺呈現相關的任何內容。例如,您可以使用 XML 檔案定義動畫、選單、樣式、顏色和活動使用者介面的版面配置。
使用應用程式資源可讓您輕鬆更新應用程式的各項特性,而不必修改程式碼。提供額外資源組合,可讓您針對各種裝置設定 (例如不同的語言和螢幕大小) 進行應用程式最佳化。
針對 Android 專案納入的每項資源,SDK 建構工具都會定義專屬整數 ID,可用於從應用程式程式碼或 XML 中定義的其他資源參照資源。舉例來說,如果應用程式含有名為 logo.png
的圖片檔 (儲存在 res/drawable/
目錄中),SDK 工具會產生名為 R.drawable.logo
的資源 ID。這個 ID 會對應至應用程式專屬的整數,可用於參照圖片,並在使用者介面中插入該圖片。
如要與原始碼分開提供資源,其中一個最重要的面向,就是能夠為不同的裝置設定提供額外資源。
舉例來說,在 XML 中定義 UI 字串後,您可以將字串翻譯成其他語言,並將這些字串儲存在不同的檔案中。接著,Android 會根據您附加至資源目錄名稱的語言限定詞,將適當的語言字串套用至 UI,例如 res/values-fr/
代表法文字串值,以及使用者的語言設定。
Android 支援許多替代資源的限定詞。限定詞是一簡短字串,您可以在資源目錄名稱中加入這個限定詞,藉此定義這些資源所用的裝置設定。
舉例來說,您可以根據裝置的螢幕方向和大小,為活動建立不同的版面配置。當裝置螢幕為縱向 (高) 時,您可能需要垂直排列按鈕的版面配置,但當螢幕為橫向 (寬) 方向時,建議您水平對齊按鈕。如要根據螢幕方向變更版面配置,您可以定義兩個版面配置,並將適當的限定詞套用至每個版面配置的目錄名稱。接著,系統會根據目前的裝置螢幕方向,自動套用合適的版面配置。
如要進一步瞭解可納入應用程式的各種資源,以及如何為不同的裝置設定建立額外資源,請參閱「應用程式資源總覽」。如要進一步瞭解最佳做法及設計完善且優質的正式版應用程式,請參閱「應用程式架構指南」。
其他資源
如要瞭解 Android 開發作業的影片和程式碼教學課程,請參閱「使用 Kotlin 開發 Android 應用程式」課程。
繼續閱讀以下相關內容:
感興趣的其他項目:
- 裝置相容性總覽
- 瞭解 Android 在不同裝置類型上的運作方式,以及如何針對各種裝置最佳化應用程式,或限制應用程式對不同裝置的可用性。
- Android 中的權限
- 瞭解 Android 如何利用權限系統,要求使用者同意應用程式使用這些 API,藉此限制應用程式存取特定 API。