Android 實現瀏覽器開啟app
我們經常看到當點選一個連結的時候,跳轉到app,比如當我們在網頁端瀏覽新聞的時候,要想檢視更多評論等就會提示你跳轉到app內開啟檢視,那是如何實現網頁中開啟app的呢?
怎麼實現?
要想實現瀏覽器內開啟app,其實我們可以看做就是開啟一個連結,只是我們普通的連結都是http或者https開頭的,如果要想開啟app,那我麼需要自定義這個schem。
首先我們來學下下uri的組成吧
scheme://host:port/path?qureyParameter=queryString
一個uri是由上面幾個部分組成的,分別是:
https://www.baidu.com/images?keyword=花兒
- scheme: scheme就是上面例子中的https
- host: 在url中就是我們的域名或者ip地址(包含埠)
- path: 主機資源的具體地址。如目錄和檔名
- params: 傳遞的引數
第一步:在AndroidManifest.xml中註冊
html中程式碼很簡單,就這麼一行,是不是html寫好了就可以開啟app了呢?當然不可以,我們需要在我們的app中註冊這個uri。現在來到app中,我們在AndroidManifest.xml中加入,我們在MainActivity中註冊。註冊程式碼如下:
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
//註冊scheme
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
//這裡myapp一定要和html中scheme一致。
<data android:scheme="myapp"/>
</intent-filter>
</activity>
第二步:在網頁中定義一個uri
所以我們可以給我們的app定義一個uri,html中程式碼如下:
<a href = 'myapp://wms.com/openwith?name=wms1993&age=24'> 開啟app </a>
當我們通過瀏覽器開啟連結的時候,就會自動開啟我們的app了,不同瀏覽器可能提示不一樣,我用uc瀏覽器開啟就會提示如下:
注意:這裡不能直接在瀏覽器位址列中直接輸入我們的url,這樣的話瀏覽器預設會給我們的url加上http,那麼就無法開啟應用了,最好是嵌在網頁中。
怎麼傳值
經過上面兩個步驟,我們就可以簡單實現通過瀏覽器開啟app了。現在我們要講的是怎麼給我們的應用傳值呢?我們知道,在http傳輸的時候,有get請求和post請求,當然這種情況下我們只能通過get請求的方式傳值,get方式傳值就是把值放在url的後面,如上面例子中,我們傳遞了兩個值
- name = wms1993
- age = 24
對於網頁中我們和普通的http沒啥區別,現在關鍵在我們app端,該怎麼接收值呢?看下程式碼:
/**
* create by wms1993
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getIntent().getAction().equals(Intent.ACTION_VIEW)) {
//通過瀏覽器開啟
Uri uri = getIntent().getData();
String name = uri.getQueryParameter("name");
String age = uri.getQueryParameter("age");
Log.e(TAG, "onCreate: name = " + name);
Log.e(TAG, "onCreate: age = " + age);
}
}
}
logcat如下:
06-12 09:57:43.064 12399-12399/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate: name = wms1993
06-12 09:57:43.065 12399-12399/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate: age = 24
當我們開啟app的時候,會呼叫onCreate方法,這裡我們看看getIntent的Action是不是ACTION_VIEW,如果是那麼是從瀏覽器中開啟的。
一些問題
經過上面的步驟,我們實現了瀏覽器開啟app以及給app傳值的操作,那麼是不是就這樣結束了呢?當然不是,這裡面還有一些小問題,加入我們app是一個新聞類的app,當我們通過網頁瀏覽新聞的時候,然後點選了新聞詳情,裡面有一個提示在app內檢視的時候,這種情況會有如下問題:
- 當我們新聞app是已經開啟的時候,我們從瀏覽器過來,當按下返回鍵的時候,是否能回到之前開啟的介面?
- 當我們的新聞app沒有開啟時,我們從瀏覽器過來,當按下返回鍵的時候,我們想回到新聞首頁而不是回到上一個應用程式,我們該怎麼做?
先來看下預設情況下是Android是如何操作的,我們現在通過瀏覽器開啟app(app之前沒開啟),這時候我們按下Home鍵,然後進入,這時候會發生什麼事?現在MainActivity.java中onCreate方法加上列印。當我們通過瀏覽器開啟app,日誌如下:
06-12 10:17:07.738 16021-16021/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate...
06-12 10:17:07.738 16021-16021/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate: name = wms1993
06-12 10:17:07.738 16021-16021/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate: age = 24
當按下Home鍵返回桌面的時候,我們在點選桌面圖示開啟app,這時候日誌如下:
06-12 10:17:59.518 16021-16021/bluetooth.wms.com.openappbybrowser E/MainActivity: onCreate...
通過日誌可以看出,這時候應用重新建立了。
預設情況下,瀏覽器喚起的頁面按返回鍵是回不到之前開啟的介面的,那麼這是為啥呢?
首先大家應該瞭解下啟動模式,我以前部落格中有一篇關於啟動模式的文章,Activity 啟動模式 ,下面我們簡單介紹下任務棧的概念。預設情況下,如果沒有對 Activity
設定 TaskAffinity
屬性,一個應用的所有 Activity
都是執行在同一個任務棧的,任務棧的名稱為應用的 PackageName
。如果從應用A啟動應用B的某個 Activity
C,則 C 會執行在 A 的任務棧中。說到這裡,相信大家應該明白為啥了吧。
當我們從Launcher啟動app時,app執行在Launcher的任務棧中,從瀏覽器中開啟app則執行在瀏覽器任務棧中,那如何解決這個問題呢?
由於從桌面點選應用會建立自己的應用棧,那麼如果我們可以把瀏覽器任務棧中的介面移動到應用本身的任務棧中。那麼怎麼將 Activity
從其他任務棧中移到自己的任務棧中呢?方法很簡單,只需要在相應的 Activity
中配置 allowTaskReparenting
屬性 為 true
即可。但是有時候我們可能不光要將一個 Activity 移過來,有時候我們需要將整個應用移動過來,這時候我們可以將allowTaskReparenting
新增到application
上,程式碼如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
//如果想將整個應用都移動到則在這裡新增
android:allowTaskReparenting="true"
android:theme="@style/AppTheme">
<activity
//如果只想移動某個Activity到則在這裡新增
android:allowTaskReparenting="true"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myapp"/>
</intent-filter>
</activity>
<activity android:name=".PageDetailActivity"/>
</application>
這樣這個問題就解決了。