經過 URL 打開 Activity

爲每一個 Activity 綁定一個 url 能夠方便的讓第三方 app 直接打開這些 Activity。也能夠方便在 app 內部進行頁面跳轉,解耦。java

背景

舉一個常見的案例,假設咱們有個產品 A,產品 A 包含 h5 網頁端和客戶端,當用戶在手機打開咱們的 h5 網頁端的時候,咱們會指望若是用戶手機安裝了咱們的客戶端,則直接打開 app,不然停留在網頁端瀏覽。android

這是一個很常見的需求,可是實現須要 h5 和 Android 的配合,本文會先說下原理,而後單獨描述 Android 端須要作的事情,最後會給一個連接說明 h5 的工做。git

原理

Android 端先給 Activity 綁定一個 url ,好比說是 myapp://main.github

用戶訪問 http://myapp.com 網頁時,h5 嘗試訪問 myapp://main,若是用戶安裝了客戶端,則會打開相應的 Activity,不然會繼續留在 h5 瀏覽網頁。後端

那麼,如何給 Activity 綁定一個 url 是在 Android 端的關鍵。app

Android 實現

建立一個空的 ViewActivity.ide

public class ViewActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

AndroidManifest.xml 裏面註冊 ViewActivity,包含一個 action 爲 android.intent.action.VIEWintent-filtergradle

<activity
    android:name=".ViewActivity"
    android:theme="@android:style/Theme.NoDisplay">
    <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>

這樣,ViewActivity 就具有了接收 myapp 協議的 android.intent.action.VIEW 事件的能力。好比說,若是某個 app 執行了下面的這段邏輯,咱們的 ViewActivity 就可能被打開。ui

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("myapp://dosomething"));
startActivity(intent);

剛纔之因此說 "可能被打開",是爲了嚴謹。由於徹底可能用戶手機上,還有另一個 app 也聲明瞭同樣協議的 intent-filter. 這時候系統就會給出一個彈出框,讓用戶選擇一個指望的應用來打開該地址。this

既然入口找到了,接下來就簡單了,無非就是實現一下 ViewActivity 處理跳轉邏輯,好比這樣。

public class ViewActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Uri uri = getIntent().getData();
        String url = uri.toString();
        if ("myapp://main".equals(url)) {
            startActivity(new Intent(ViewActivity.this, MainActivity.class));
        } else if ("myapp://user".equals(url)) {
            startActivity(new Intent(ViewActivity.this, UserActivity.class));
        }
        finish();
    }
}

可是上面這種,這是一個理想的狀況,由於現實狀況會複雜的多。好比說會遇到傳參問題,打開一個 UserActivity 可能都是須要指定一個 userId 的。不過再怎麼複雜,無非就是對一個 url 的解析。

下面會介紹一個我寫的開源項目,省掉了解析 url 的麻煩,下面會基於這個庫來講明。

這個庫叫 ActivityRouter,經過給 Activity 添加註解來綁定 url. 首先咱們要把庫添加到項目裏面來, 須要修改兩個 build.gradle 文件。

項目根目錄的 build.gradle

buildscript {
  dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7'
  }
}

app 項目的 build.gradle

apply plugin: 'android-apt'

dependencies {
    compile 'com.github.mzule.activityrouter:activityrouter:1.1.1'
    apt 'com.github.mzule.activityrouter:compiler:1.1.1'
}

這樣,等項目 sync 完 ActivityRouter 就已經被集成在項目裏面了。

此外還須要改一個配置,以前在 AndroidManifest.xml 上註冊的 ViewActivity 如今要換成 ActivityRouter 裏面自帶的 Activity,這樣 ActivityRouter 纔有機會處理相關的 Intent 事件。修改完的 AndroidManifest.xml 以下:

<activity
    android:name="com.github.mzule.activityrouter.router.RouterActivity"
    android:theme="@android:style/Theme.NoDisplay">
    <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>

接下來就是去修改須要綁定 url 的 Activity,添加註解便可,一個典型的實現以下:

@Router("main")
public class MainActivity extends Activity {
}

一個須要參數的 Activity 能夠這樣聲明:

@Router("user/:userId") // :userId 表明參數名爲 userId
public class UserActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String userId = getIntent().getStringExtra("userId"); // 獲取參數 userId
    }
}

也能夠給參數指定類型,好比說常見的 id 爲 long 型.

@Router(value = "user/:userId", longExtra = "userId")

這樣咱們就能夠經過 myapp://main 來訪問 MainActivity, myapp://user/89757 來訪問 UserActivity 而且 userId = 89757 了。

H5 實現

如上文所說網頁自動跳轉到 app 須要 h5 配合,因爲 h5 已經超越了 Android 的範疇,這邊就直接貼個連接。

http://t.cn/RqMTBDZ

http://t.cn/RzOQWGU

App 內應用場景

除了第三方 app 跳轉場景外,還能夠在 app 內部 Activity 跳轉時採用 Router 來實現,好比在 Android 端和後端約定好頁面對應的 url,後端在發送 push 的時候,就能夠發送特定的 url,客戶端只須要處理打開 url 便可,能夠有效減小 push 通知的適配工做。相關 API 以下:

Routers.open(Context, String)
Routers.open(Context, Uri)

結語

哈哈,感謝你看到這裏。

相關文章
相關標籤/搜索