Android – 使用特定的URL開啟應用程式

Android – 使用特定的URL開啟應用程式

在iPhone、Android或Windows Phone 7的環境都支援透過URL中特定的Schema來啟動特定的應用程式,

例如:「zune:\\」、「contnet:\\」…等,該目的告訴系統有一特定的連結要被啟動,請系統動找到註冊

對應該Schema的程式並且啟動它,如果想要夾參數帶入應用程式中,寫法就如同透過QueryString的方式

將Key/Value帶入URL中,由程式啟動時根據特定的參數取得值來完成任務。

 

要完成這樣的功能,在開發Android時要修改那些部分與概念,往下來概要的說明:

 

AndroidManifest.xml File

    該份檔案描述整個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的相同,但移動到不同的命名空間即不同。如下圖:

       image

       可透過setComponent())" target=_blank>setClass()setClassName()getComponent()來操作ComponentName的資料。

 

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 時區設置發生了變化。

      另外,Action也決定的Intent的資料結構,特別是:dataextras。然而,Action除了上述Android API定義的之外,

      (隨著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://來擷取它開放出來的資源。

       透過setData()來定義URI,使用setType()定義 MIME類型或是setDataAndType()同時定義二者。   

 

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夾帶參數給已安裝於手機中的應用程式,再與後端系統

進行互動,既可以做到與設備的結合更可以讓部分安全性得到保護。

 

References:

Android intent filter, associate app with file extension (重要)

Application Fundamentals

定義Anrdoid清單-AndroidManifest

Intent & Intents and Intent Filters

MIME types and ACTION_SEND intent chooser

Jollen 的 Android 教學,#28: HelloIntentSelect - 內容選擇器(Content Chooser)

Launching Your Own Application via a Custom URL Scheme

Launching Other Apps within an iPhone Application

Custom URL Scheme - iPhone & Android

How to implement my very own URI schema on Android

android custom url scheme..? & How do I launch my app via a custom URL in an email

Launch custom android application from android browser & Defining custom URL schemes for your AIR mobile applications

 

Dotblogs Tags: