Android – 使用特定的URL開啟應用程式
在iPhone、Android或Windows Phone 7的環境都支援透過URL中特定的Schema來啟動特定的應用程式,
例如:「zune:\\」、「contnet:\\」…等,該目的告訴系統有一特定的連結要被啟動,請系統動找到註冊
對應該Schema的程式並且啟動它,如果想要夾參數帶入應用程式中,寫法就如同透過QueryString的方式
將Key/Value帶入URL中,由程式啟動時根據特定的參數取得值來完成任務。
要完成這樣的功能,在開發Android時要修改那些部分與概念,往下來概要的說明:
該份檔案描述整個Android應用程式的所有功能、使用的Library、要求手機設備提供的權限控制與存取範圍,
因此,今天要增加對特定URL的處理,也正是從該檔案下手告訴Android系統該應用程式將對某特定的URL Schema
有所反應,當系統接收到該URL時自動啟動應用程式。
A. Intent:
Android應用程式裡三個重要元件:activities、services與boardcast services,它們之間傳遞訊息的物件即是:Intent。
Intent可被不同的應用程式建立當作互相溝通的主要介面,它本身是個物件用於保存訊息交換的內容、Anrdoid固定參等,
在三種不同元件使用方式也有所不同,如下:
‧Activity:
透過Context.startActivity()將Intent帶到指定的Activity之中;並且實作Activity.startActivityForResult()接受由另一個
Activity回傳的Intent內容(至於回傳的內容會透過setResult()的方式將Intent放入);
‧Service:
透過Context.startService()去初始化Service並且將Intent傳遞給Service讓它進行處理;另外可透過Context.bindService()
去選擇特定的Service與Intent互相連接;
‧Boardcast Service:
例如透過Context.sendBoardcast()將Intent發送給任何的Boardcast,或是透過Context.sendStickyBroadcast()來送給有興
趣的Boardcast service。由於Intent裡需指定特定的system code不然該Intent就沒有被特定的boardcast service查覺到。
了解Intent怎麼在三種元件中使用後,接下來針對Intent物件的結構進行說明:
A-1. Component Name:
該屬性為ComponentName物件,它代表Intent目標的完整名稱,例如:com.example.project.app.FreneticActivity;
例如:由Main的activity移到Second的activity,然而在Second收到Intent它的ComponentName即為完整的Second命
名空間,而Package即與AndroidManifest.xml的相同,但移動到不同的命名空間即不同。如下圖:
A-2. Action:(重要)
Action是Intent中重點部分,它定義該Intent要負責的任務是什麼,例如:我想要撥打電話,即會指定該Intent的Action
為ACTION_CALL並在setData指定Uri為tel:0932xxxxxx,啟動並直接撥打電話。相對的,如果是broadcast receiver一樣透
過Action的指定,讓Intent告訴Android系統當收到電量過低時,要通知自己註冊的broadcast receiver來完成指定的任務。
Constant | Target component | Action |
ACTION_CALL | activity | 啟動一個撥打電話。 |
ACTION_EDIT | activity | 顯示資料提供用戶有編輯能力。 |
ACTION_MAIN | activity | 預設第一個啟動的activity,沒有資料輸入和回傳資料輸出。 |
ACTION_SYNC | activity | 設備與伺服務同步資料。 |
ACTION_VIEW | activity | 顯示資料不支援編輯能力。 |
ACTION_DIAL | activity | 啟動撥號程式並填入撥號的號碼。 |
ACTION_BATTERY_LOW | broadcast receiver | 當電量過低時發出的警告。 |
ACTION_HEADSET_PLUG | broadcast receiver | 設備已經插入了耳機,或將它拔掉。 |
ACTION_SCREEN_ON | broadcast receiver | 螢幕被打開。 |
ACTION_TIMEZONE_CHANGED | broadcast receiver | 時區設置發生了變化。 |
(隨著Android版本不同有更多的Action可用),其實也可以自訂。
A-3. Category:
用於描述該組件(activity, service, broadcast service)要處理的Intent類型,然而,該Category可任意數量的去描述該組件
要處理的Intent對象。如下列的描述類型:
Constant | Meaning |
CATEGORY_BROWSABLE | 目標activity可以安全地被透過Browser中顯示的link(或uri)來啟動,例如:透過image或mail來啟動對應的應用程式。 |
CATEGORY_GADGET | activity可以被嵌入至另一個hosts gadgets中的activity。 |
CATEGORY_HOME | activity呈現於HOME screen,也就是當用戶按下實體鍵盤中的HOME時,用戶第一個看到的畫面。例如:GO桌面即是這種類型的組件。 |
CATEGORY_LAUNCHER | activity是task的初始activity,並且是application launcher的top-level。該類型常設定應用程式第一個啟動的activity,並且配合ACTION_MAIN一同定義該activity。 |
CATEGORY_PREFFRENCE | 目標activity是一個preference panel。 |
A-4. Data:
利用URI為概念的傳遞格式,定義了URI與MIME的資料類型。不同的Action搭配不同類型Data格式。例如:ACTION_EDIT,
Datal部分需要包括要編輯的文件的URI;ACTION_CALL則Data為要撥打電話的URI:tel:0932xxxxx;如果是ACTION_VIEW,
則Data為http:URI指定的activity收到後將下載或開啟對應的程式將資料顯示出來。
另外,在找到Intent的對應後,除了取出URI之外,更要看它定義的MIME為何種類型,例如:video/mpeg,則代表要開啟
的資料類型為mpeg的影片資料。
通常透過URI也可以推斷出相關的應用,例如:Content://即是Android的Content Provider機制,應用程式之間如果有實作
支援Content Provider那麼別的應用程式即可以透過Content://來擷取它開放出來的資源。
A-5. Extras:
它是一個Key/Value的資料格式,當作Intent要夾帶參數的用途。某些Action透過特定的Extras來傳遞給目標的activity,
做為初始化或識別的任務,例如:ACTION_TIMEZONE_CHANGED有指定的extra key:time-zone或者是ACTION_HEADSET_PLUG
有指定的extra key:state。這樣做的目的在於讓Intent不一定只能依靠URI傳遞參數,所以當二個Activity互動時,也可以
透過該方式來進行資料的傳遞。
A-6. Flags:
Flags通常用於指示Android系統如何執行activity,例如:activity屬於那一個Task來執行;或者如何對待啟動的activity等,
也可以把一些特殊定義的標籤設定於此,讓Intent可以夾帶特定的識別代碼。
介紹了Intent後,其實可以了解Android在三種組件互動或是透過Browser互動,均是透過Intent概念來進行互動。因此,
最後就介紹如果要讓自己的應用程式可以接受URL Schema所影響的Intent要設定的參數有那些,進一步去了解Intent-Filter的特性。
B. Intent-filter:
Intent在Anrdoid開發文件裡可分成二個部分:
(1) Explicit intents:Intent指定特定目標對象,通常都是內部Project中的activity或是其他組件互相溝通。 。
(2) Implicit intents:Intent不需要特定目標對象,通常用於激活其他應用程式的組件。
Android在使用Explicit intents時,由於目標比較明確比較沒有問題,但在遇到Implicit intents時,系統必須尋找到最匹配的組件
來處理Intent,例如:在AndroidManifest.xml定義Activity、Service或Broadcast Receiver來處理特定的Intent(Intent-Filter)。
透過Intent-Filter定義了組件需要處理的explicit、implicit Intents,但如果組件沒有定義Intent-Filter的話,該組件只能處理explicit
intents。
然而,每一個Intent-Filter描述組件(activity, service, broadcast receiver)處理的目標與特性,每一個filter是實例化
IntentFilter
類別,filter有三個主要的重點:(1). action;(2). data;(3). category;
‧action:
1: <action android:name="string" />
定義該組件要面對的Action對象為何。name屬性通常是使用Intent描述的Action屬性,自己的應用程式裡如果有自訂要處理的
Action也可以透過自訂的字串常數來說明。在Intent-Filter中至少要有一個<action>標籤。
‧category:
1: <intent-filter>
2: <category android:name="android.intent.category.DEFAULT" />
3: <category android:name="android.intent.category.BROWSABLE" />
4: </intent-filter>
上述提到有關intent中的category描述不太一樣,在intent中是直接使用上述提到的常數,但在AndroidManifest.xml中定義的
需要使用完整的字串來加以描述,例如:android.intent.category.BROWSABLE與intent中使用的CATEGORY_BROWSABLE相似。
‧data:
1: <intent-filter>
2: <data android:mimeType="video/mpeg" android:scheme="http" />
3: <data android:mimeType="audio/mpeg" android:scheme="http" />
4: </intent-filter>
每一個<data>定義了處理的URI與data type(MIME media type),屬性包括:schema、host、port與path,其格式如下:
URI:{schema://host:port/path},定義Android如收到相同URI的格式需通當定義這個data的組件;
[注意]
‧透過URL啟動的與透過手動啟動的應用程式二者是不同的,前者是依賴著啟動者的執行緒所啟動,後者則是獨立的執行緒,
二者其實控制的功能都是一樣的,最大的差異在於透過URL啟動的應用程式,在長按「實體home鍵」要切換回應用程式時,
它不會出現暫存清單中。
〉範例說明:
1. 實作一個網頁裡面有一個特定的URL,例如:「myapp://Order?SID=201112301333001」;
1: <html xmlns="http://www.w3.org/1999/xhtml" >
2: <head runat="server">
3: <title>使用特定的URL開啟應用程式</title>
4: </head>
5: <body>
6: <form id="form1" runat="server">
7: <div>
8: <!-- 定義特定的URL與Schema -->
9: <a href="myapp://Order?SID=201112301333001">您有一封新單據。</a>
10: </div>
11: </form>
12: </body>
13: </html>
2. 建立透過URL啟動後要處理的Activity與擷取參數的功能;
在OnCreate事件中建立取得由URL啟動應用程式帶入的值,這些資料按照Android的作法會放置於Intent的物件中。
1: @Override
2: protected void onCreate(Bundle savedInstanceState) {
3: super.onCreate(savedInstanceState);
4: setContentView(R.layout.urlopen);
5: //取得要顯示參數的TextView物件
6: TextView tView = (TextView) findViewById(R.id.textView1);
7:
8: //取得URL所帶進來的Intent物件
9: Intent tIntent = this.getIntent();
10: //取得Schema,值為:myapp
11: String tSchema = tIntent.getScheme();
12: //取得URL
13: Uri myURI = tIntent.getData();
14: if (myURI != null) {
15: //取得URL中的Query String參數
16: String tValue = myURI.getQueryParameter("SID");
17: tView.setText(tValue);
18: }
19: }
3. 定義AndroidManifest.xml中支援URL的Schema與互相的相關參數;
1: <application android:icon="@drawable/icon" android:label="@string/app_name">
2: <!-- 主程式-->
3: <activity android:name=".Main"
4: android:label="@string/app_name">
5: <intent-filter>
6: <action android:name="android.intent.action.MAIN" />
7: <category android:name="android.intent.category.LAUNCHER" />
8: </intent-filter>
9: </activity>
10: <!-- 接收由URL啟動應用程式後第一個要進入的Activity -->
11: <activity android:name=".Second">
12: <intent-filter>
13: <!-- 宣告該Activity的Action主要類型 -->
14: <action android:name="android.intent.action.VIEW"/>
15: <!-- 定義該Activity支援瀏覽模式 -->
16: <category android:name="android.intent.category.BROWSABLE"/>
17: <category android:name="android.intent.category.DEFAULT"/>
18: <!-- 定義要處理的URL Schema -->
19: <data android:scheme="myapp"/>
20: </intent-filter>
21: </activity>
22: </application>
======
以上是介紹如何透過特定的URL來啟動自己的應用程式,由於該用途很適合結合目前公司既有程式,
因為不想特別公開連線資訊出來時,透過URL夾帶參數給已安裝於手機中的應用程式,再與後端系統
進行互動,既可以做到與設備的結合更可以讓部分安全性得到保護。
沒有留言:
張貼留言