關於Android路由的實現

來源:互聯網
上載者:User

標籤:公司   方式   use   自己   自動   processor   cte   kde   運行時   

  先說一下背景,目前有需求從外部包括其他應用和WEB跳轉到我們自己的APP,就這麼個簡單的需求……

  要實現這種外部跳轉的功能,我們可以理解為打算跳轉的一方有多少方式通知到APP進行相對的響應行為。所以,如果是應用之間的跳轉,則有多種,你可以直接通過包名和具體的類名去開啟已經exported=true的Activity,又或者直接通過Android的廣播通知進行相關的APP,又或者通過自訂的Uri去開啟應用。但是如果設計到Web開啟外部應用的話,目前只有一種辦法,那就是自訂應用的Uri進行攔截,系統會自動調起相應的組件響應這個Uri。

  但是,要做這種需求,很少會僅僅是完成對外部的支援而已,通常也要進行一定的內部邏輯跳轉映射。所以要做這種需求通常分為兩個種,一種是對內的(應用內部自己的跳轉邏輯),一種對外的(其他應用以及Web跳轉邏輯)。

  我們先說一下對外的情形,由於考慮到統一性,我們目前只有URI這種手段可以使用了。下面我們一一來說

  1、對外跳轉說明

  1.1、關於URI的說明。

  首先,我們得瞭解一下Uri,這裡直接引用 https://en.wikipedia.org/wiki/URL 的說明。為了方便說明,我稍稍修改一下,大概的格式如下:

  scheme:[//host[:port]][/path][?query][#fragment]

  首先,scheme是必須的,其他的都是不必須的,但是對於跳轉來說,顯然不可能,因為你要從這個url中取出跳轉相關的資訊。所以,通常一定要要有host和query。我們經常看到一些開源的路由實現,都會支援所謂的restful風格的url,比如:wytings://app/{city}/{id} ,但我個人認為是沒有必要的。主要是因為這種外部跳轉的行為,通常量比較少,其次應該盡量統一而且方便,而不是為了追求各種技術炫酷…我刻意看了的scheme就甚合我意~都是類似於這種格式:weixin://qrscan?a=1&b=2

  我們進行一下歸納,就可以進行應用的uri定義了,首先scheme是必須項,看個人和公司要求,比如接下來要舉的例子,我定義的scheme為wytings,然後支援的模組都集中於host欄位,具體參數則全部通過query補充。比如:wytings://user?uin=10000 開啟個人頁面,wytings://stockDetail?marketcode=hk&stockcode=00376 開啟股票詳情頁面等等。

  要是對外部的支援,通常我們不會對每一個要支援的Activity都進行相應的intent-filter限制,而是定義一個公用的Activity進行所有外部請求的攔截形如:

 1     <activity 2             android:name=".activity.SchemeFilterActivity" 3             android:exported="true" 4             android:theme="@android:style/Theme.NoDisplay"> 5  6             <intent-filter> 7  8                 <action android:name="android.intent.action.VIEW" /> 9 10                 <category android:name="android.intent.category.DEFAULT" />11                 <category android:name="android.intent.category.BROWSABLE" />12 13                 <data android:scheme="wytings" />14 15             </intent-filter>16 17             <intent-filter18                 android:autoVerify="true"19                 tools:targetApi="m">20                 <action android:name="android.intent.action.VIEW" />21 22                 <category android:name="android.intent.category.DEFAULT" />23                 <category android:name="android.intent.category.BROWSABLE" />24 25                 <data26                     android:host="native.app.wytings.com"27                     android:scheme="http" />28                 <data29                     android:host="native.app.wytings.com"30                     android:scheme="https" />31             </intent-filter>32         </activity>

  我們對這個Activity的定義進行一下說明:

  a、android:exported這個屬性其預設是false就是對外不開放,我們必須要設定為true,因為我們要讓外部能夠對其進行訪問。

  b、android:theme="@android:style/Theme.NoDisplay" 由於是作為攔截的Activity,所以,沒必要展示,但是這個NoDisplay的theme要求必須在onResume前finish掉Activity,否則要報錯。

  c、第一個intent-filter自訂scheme為wytings,也就是攔截該類uri。

  d、第二個scheme為http,但是加了特別的host=nativ.app.wytings.com,進一步詳細攔截url為:http://nativ.app.wytings.com 的url。為什麼要攔截這種url,通常情況下不用,但是特殊情況下,有時候自訂的scheme可能失效,所以而外再加層保障,當然,也要與調用方預定好url格式,比如:http://nativ.app.wytings.com/stockDetail?marketCode=hk&stockCode=00376,由於host已經被定義為別的,所以我們把具體模組定義在path裡面,參數依然保留在query中。

  再來看看SchemeFilterActivity的實現情況:

  

/** * Created by rex on 06/10/2017. * * @author [email protected] */public class SchemeFilterActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Uri uri = getIntent().getData();        Log.i("wytings", "uri = " + uri);        String scheme = uri.getScheme();        if ("http".equals(scheme) || "https".equals(scheme)) {            String routeModule = uri.getLastPathSegment();            if (!TextUtils.isEmpty(routeModule)) {                RouteManager.getInstance().build(routeModule + "?" + uri.getQuery()).go(this);            }        } else {            RouteManager.getInstance().build(uri.toString()).go(this);        }        finish();    }}

  大體就是攔截,然後通過內部的RouteManager進行解析處理跳轉。RouteManager怎麼處理和實現就太細節了,總的來說,這個Manager的職責就是把uri翻譯成具體的Intent,然後啟動相應的Activity。有興趣的同學可以自己去看看本篇文章的所有源碼:

  https://github.com/wytings/AndroidRoute

  

  2、對內跳轉說明

  由於是應用內的實現,所以基本上,你想怎麼實現就怎麼實現。但是,無論多麼變幻莫測,都繞不開一個核心那就是建立路由映射關係,開啟相關頁面,取出請求參數這三大步驟。我們逐個來分析一下。

  2.1、建立路由映射關係

  這個是為了能夠知道特定的url到底應該展示哪個頁面。通常建立一個Map,然後尋找。

  2.3、開啟相關頁面

  在Android中,開啟一個頁面總是有自己的一套邏輯,系統那一套則是通過Intent去啟動相應的組件展示。

  2.4、取出參數

  這個步驟,還是基於系統的Intent方式,要通過intent.getXXXExtra來取出相關參數。

  這麼一看好像,也沒什麼難度。也確實沒什麼難度,就單純實現功能來說。那痛點在哪呢?痛點在於你決定使用註解去做這件事……為什麼要用註解?因為為了哪一丁點潔癖,解藕的潔癖。結果掉進坑裡了…

  用註解理論上,也還好,遍曆反射嘛,而且我個人測試了一下,就目前的機器真的感受不出來。當然再怎麼樣,也沒在編譯時間直接產生相關代碼來得快到是真的……

   於是乎,進入第三個大難題,那就是進行編譯時間產生代碼,類似於ButterKnife一樣,在編譯期就產生相關代碼,而不是在運行時通過反射來一一給變數賦值。

  這裡就涉及到一個東西,那就是Java 的 AbstractProcessor,這個類是在編譯時間產生代碼最關鍵的類。要將這個得再開一篇《關於Java註解實現編譯時間產生代碼》的文章了。同學們可以網上搜尋一下基本知識,然後再看這個項目中的代碼,我自己也看了很多關於註解的文章,但是很遺憾,我沒看到哪篇是值得捧的,同樣也沒看到那篇值得噴的……我現在也沒時間專門寫篇關於註解的文章,但是可以給個方向,那就是先學會調試,AnnotatioProcessor的調試,跟不同java調試有點區別(自己google一下),然後就可以自己摸索了。另外,我審視了一下,我寫的Annotation compiler還是蠻清晰的,你也可以試著看看。

  最後,再說一遍,項目地址:AndroidRoute

  自己跑一下,升讀十年書!  

 

關於Android路由的實現

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.