好久好久沒寫過文章了,一是最近專案太忙了,沒時間寫。二是也沒有時間學習新的東西,想寫點什麼卻又無從下筆。一味的去寫這個API怎麼用,那個新技術怎麼用,又顯的沒意思。沒有專案經驗總結的技術知識講解,總感覺有些蒼白。最近在做混合App開發這塊,從開始的ionic 框架,到後來的mui框架,讓我在混合開發這塊有了更深的理解,如果在這塊要寫點什麼無非漫天蓋地的這個指令怎麼用,那個模版怎麼用,資料怎麼進行雙向繫結,等等,但是這些網上已經很多資料了,等不太忙了,我想我會總結一篇這些框架的使用心得吧。但是我今天不講這個,我們來談一談在原生app中(iOS android)如何使用動態路由機制來搭建整個app的框架。
路由機制在web開發中是比較常見的,app開發中還是很少聽到這種概念的,目前有些大公司採用的元件化開發(手淘,攜程,蘑菇街等),倒是跟我們講的有很多相同之處,不過它們的比較複雜,而且網上很多元件化開發,路由機制,沒有一個能給出完整程式碼示例的,看著讓人云裡霧裡的。索性自己就借鑑它們的思想,加上一點個人的理解,搞出了一個簡單實用的可行性demo出來。我們主要介紹以下三方面內容:
1 什麼是動態路由
2 它能解決我們什麼問題
3 如何在專案中實現
一 什麼是動態路由
原生開發沒這概念,我們藉助angular路由機制來解釋這一概念,所謂路由,就是一套路徑跳轉機制,事先通過配置檔案定義好一個路徑對映檔案,跳轉時根據key去找到具體頁面,當然angular會做一些快取,頁面棧的管理等等一些操作,它大致的定義是這樣的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
angular.module('app',[]) .config('$routeProvider',function ($routeProvider) { $routeProvider .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .ontherwise({ redirective:'/' }) }) |
config函式是一個配置函式。在使用
$routeProvider這樣的一個服務。when:代表當你訪問這個“/”根目錄的時候 去訪問 templateUrl中的那個模板。 controller可想已知,就是我們配套的controller,就是應用於根目錄的這個 模板時的controller。
ontherwise 就是當你路徑訪問錯誤時,找不到。最後跳到這個預設的 頁面。
為此我們可以總結一下幾個特點:
1 一個對映配置檔案
2 路徑出錯處理機制
這就是路由的基本意思,我們看看,在原生開發中,採用此種方式,他能解決我們什麼問題。
二 它能解決我們什麼問題
首先我們來比較一下我們以前的結構模式以及與 加入路由機制後的專案結構,實現路由機制,不僅需要一個對映檔案,還需要一套路由管理機制,那麼採用路由機制,我們的專案架構就跟原來不一樣了,如下圖:
接下來我們看一下平時我們採用的頁面跳轉方法:
iOS 下
1 2 |
[self presentViewController:controller animated:YES completion:nil]; [self.navigationController pushViewController:controller animated:YES]; |
android 下
1 |
Intent intent = new Intent(this, A.class); startActivity(intent); startActivityForResult(Intent intent, Int requestCode) |
我們看一下它有哪些缺點:
(1)都要在當前頁面引入要跳轉頁面的class 類。這就造成了頁面的耦合性很高。
(2)遇到重大bug,不能夠及時的修復問題,需要等待更新發版後才能解決。
(3)推送訊息,如果入口沒有關與頁面的引入處理,則不能跳轉到指定頁面。
引入路由機制後我們能否解決這些問題呢?
試想一下,如果我們通過一個配置檔案來對映頁面跳轉關係,而且通過反射機制來取消標頭檔案的引入問題,是不是我們就可以解決以上那些弊端了呢,比如,我們線上應用出現bug, 導致某個頁面一開啟,app就跪了,那我們是不是就可以通過更新路由配置檔案,把它對映到另一個頁面去:一個錯誤提示檔案,或者一個線上H5能實現相同功能的頁面。這樣的話,原生app也具有了一定的動態更新能力,其實想想還有很多好處,比如專案功能太多原生開發要很長時間,但是領導又急著要上線,那麼我們是不是就可以先開發一個網頁版的模組,app路由對映到這個web頁面,讓使用者先用著,等我們原生開發完了,然後再改一下對映檔案,沒升級的依舊用H5的路由,升級的就用原生的路由,如果H5頁面我們要廢棄了,那我們整體就可以路由到一個升級提升的頁面去了。
總結一下路由機制能解決我們哪些問題:
1 避免引入標頭檔案,是頁面之間的依賴大大變少了(通過反射動態生成頁面例項)。
2 線上出現重大bug,給我們提供了一個及時修補的入口
3 網頁和原生切換更方便,更自由。
4 可以跳轉任意頁面 例如我們常用的推送,要開啟指定的頁面,以前我們怎麼做的,各種啟動判斷,現在呢,我們只要給傳送訊息配個路由路徑就行了,開啟訊息,就能夠跳轉到我們指定的頁面。
等等,其它好處自行發掘。
三 如何在專案中實現
說了這麼多概念性問題,下面我們就用程式碼來實現我們的構想, 下面先以IOS平臺為例:
我們先看一下demo結構
說明:WXRouter 路由管理檔案
demo 路由使用示例
urlMap.plist 路由配置檔案
我們主要講解一下 WXRouter裡面的幾個檔案,以及ViewController檔案,還有urlmap.plist檔案,其他請下載示例demo,文末我會給出demo地址。
1 2 3 4 5 6 7 |
#import #import @interface WXRouter : NSObject +(id)sharedInstance; -(UIViewController *)getViewController:(NSString *)stringVCName; -(UIViewController *)getViewController:(NSString *)stringVCName withParam:(NSDictionary *)paramdic; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#import "WXRouter.h" #import "webView.h" #import "RouterError.h" #import "PlistReadUtil.h" #define SuppressPerformSelectorLeakWarning(Stuff) \ do { _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \ Stuff; \ _Pragma("clang diagnostic pop") \ } while (0) @implementation WXRouter +(id)sharedInstance { static dispatch_once_t onceToken; static WXRouter * router; dispatch_once(&onceToken,^{ router = [[WXRouter alloc] init]; }); return router; } -(UIViewController *)controller:(UIViewController *)controller withParam:(NSDictionary *)paramdic andVcname:(NSString *)vcName { SEL selector = NSSelectorFromString(@"iniViewControllerParam:"); if(![controller respondsToSelector: selector]){ //如果沒定義初始化引數方法,直接返回,沒必要在往下做設定引數的方法 NSLog(@"目標類:%@未定義:%@方法",controller,@"iniViewControllerParam:"); return controller; } if(paramdic == nil) { //如果引數為空 URLKEY 頁面唯一路徑標識別 paramdic = [[NSMutableDictionary alloc] init]; [paramdic setValue: vcName forKey:@"URLKEY"]; SuppressPerformSelectorLeakWarning([controller performSelector: selector withObject:paramdic]); } else { [paramdic setValue: vcName forKey:@"URLKEY"]; } SuppressPerformSelectorLeakWarning( [controller performSelector:selector withObject:paramdic]); return controller; } -(UIViewController *)getViewController:(NSString *)stringVCName { NSString *viewControllerName = [PlistReadUtil plistValueForKey: stringVCName]; Class class = NSClassFromString(viewControllerName); UIViewController *controller = [[class alloc] init]; if(controller == nil){ //此處可以跳轉到一個錯誤提示頁面 NSLog(@"未定義此類:%@",viewControllerName); return nil; } return controller; } -(UIViewController *)getViewController:(NSString *)stringVCName withParam:(NSDictionary *)paramdic { UIViewController *controller = [self getViewController: stringVCName]; if(controller != nil){ controller = [self controller: controller withParam:paramdic andVcname:stringVCName]; } else { //異常處理 可以跳轉指定的錯誤頁面 controller = [[RouterError sharedInstance] getErrorController]; } return controller; } @end |
說明:通過反射機制根據傳入的string來獲取 viewcontroller例項,實現了兩個方法,一個是不需要傳入引數的,一個是需要傳入引數的,當跳轉到第二個頁面需要傳值 就使用第二個帶引數的方法,所傳的值通過NSDictionary來進行封裝,跳轉後的頁面通過實現
-(void)iniViewControllerParam:(NSDictionary *)dic
方法來獲取傳過來的引數。
1 2 3 4 5 6 |
#import @interface PlistReadUtil : NSObject @property(nonatomic,strong) NSMutableDictionary *plistdata; +(id)sharedInstanceWithFileName:(NSString *)plistfileName; +(NSString *)plistValueForKey:(NSString *)key; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#import "PlistReadUtil.h" @implementation PlistReadUtil +(id)sharedInstanceWithFileName:(NSString *)plistfileName { static dispatch_once_t onceToken; static PlistReadUtil * plistUtil; dispatch_once(&onceToken,^{ plistUtil = [[PlistReadUtil alloc] init]; NSString *plistPath = [[NSBundle mainBundle] pathForResource: plistfileName ofType:@"plist"]; plistUtil.plistdata = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath]; }); return plistUtil; } +(NSString *)plistValueForKey:(NSString *)key { PlistReadUtil *plist = [PlistReadUtil sharedInstanceWithFileName: @"urlMap"]; return [plist.plistdata objectForKey: key]; } @end |
說明:路由配置檔案讀取工具類,我這裡讀取的是plist 檔案,我這裡也可以讀取json,或則訪問網路獲取後臺伺服器上的路由配置檔案,這個根據我們業務需求的不同,可以新增不同的讀取方法。
1 2 3 4 5 6 |
#import #import @interface RouterError : NSObject +(id)sharedInstance; -(UIViewController *)getErrorController; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#import "RouterError.h" #import "WXRouter.h" @implementation RouterError +(id)sharedInstance { static dispatch_once_t onceToken; static RouterError * routerError; dispatch_once(&onceToken,^{ routerError = [[RouterError alloc] init]; }); return routerError; } #pragma mark 自定義錯誤頁面 此頁面一定確保能夠找到,否則會進入死迴圈 -(UIViewController *)getErrorController { NSDictionary *diction = [[NSMutableDictionary alloc] init]; [diction setValue: @"https://themeforest.net/item/octopus-error-template/2562783" forKey:@"url"]; UIViewController *errorController = [[WXRouter sharedInstance] getViewController: @"MSG003" withParam:diction]; return errorController; } @end |
說明:在讀取配置檔案時如果沒有讀到相應的路徑,或者未定義相應的class,我們可以在這裡處理,我這邊處理的是如果出現錯誤,就返回一個webview頁面,我們可以在專案裡寫一個統一的錯誤處理webview頁面,其實每個頁面預設都新增了一個引數[paramdic setValue:vcName forKey:@"URLKEY"];
就是這個URLKEY,這個key標示配置檔案中每個跳轉動作的key,這個key是唯一的,我們可以根據不同的URLKEY然後通過後臺統一的一個介面來判斷跳轉到不同的錯誤處理H5頁面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
#import "ViewController.h" #import "view2.h" #import "WXRouter.h" #import "PlistReadUtil.h" @interface ViewController () @end @implementation ViewController -(void)viewDidLoad { [super viewDidLoad]; UILabel *lable = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 100, 50)]; lable.textColor = [UIColor blueColor]; lable.text =@"hello word"; [self.view addSubview: lable]; UIButton *button = [[UIButton alloc] initWithFrame: CGRectMake(0, 50, 200, 50)]; [button setTitle: @"訪問view1" forState:UIControlStateNormal]; [button setTitleColor: [UIColor blackColor] forState:UIControlStateNormal]; button.tag = 1; [button addTarget: self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview: button]; UIButton *button2 = [[UIButton alloc] initWithFrame: CGRectMake(0, 110, 200, 50)]; [button2 setTitle: @"訪問view3" forState:UIControlStateNormal]; [button2 setTitleColor: [UIColor blackColor] forState:UIControlStateNormal]; button2.tag = 2; [button2 addTarget: self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview: button2]; UIButton *butto3 = [[UIButton alloc] initWithFrame: CGRectMake(0, 170, 200, 50)]; [butto3 setTitle: @"訪問webview" forState:UIControlStateNormal]; [butto3 setTitleColor: [UIColor blackColor] forState:UIControlStateNormal]; butto3.tag = 3; [butto3 addTarget: self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview: butto3]; UIButton *button4 = [[UIButton alloc] initWithFrame: CGRectMake(0, 230, 200, 50)]; [button4 setTitle: @"訪問wei定義的頁面" forState:UIControlStateNormal]; [button4 setTitleColor: [UIColor blackColor] forState:UIControlStateNormal]; button4.tag = 4; [button4 addTarget: self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview: button4]; } -(void)back:(UIButton *)btn { switch (btn.tag) { case 1: { NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; [dic setValue: @"nihao shijie" forKey:@"title"]; UIViewController *controller = [[WXRouter sharedInstance] getViewController: @"MSG001" withParam:dic]; [self presentViewController: controller animated:YES completion:nil]; } break; case 2: { NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; [dic setValue: @"nihao shijie" forKey:@"title"]; UIViewController *controller = [[WXRouter sharedInstance] getViewController: @"MSG002" withParam:dic]; [self presentViewController: controller animated:YES completion:nil]; } break; case 3: { NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; [dic setValue: @"https://www.baidu.com" forKey:@"url"]; UIViewController *controller = [[WXRouter sharedInstance] getViewController: @"MSG003" withParam:dic]; [self presentViewController: controller animated:YES completion:nil]; } break; case 4: { UIViewController *controller = [[WXRouter sharedInstance] getViewController: @"MSG005" withParam:nil]; [self presentViewController: controller animated:YES completion:nil]; } default: break; } } -(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end |
說明:這個是使用示例,為了獲取最大的靈活性,這裡我並沒有把跳轉動作presentViewcontroller,pushViewController,以及引數的組裝封裝在路由管理類裡。看過很多大神寫的路由庫,有些也通過url schema的方式。類似於:xml:id/123/name/xu,這樣的路徑方式,但是個人感覺,如果介面之間傳遞圖片物件,或者傳巢狀的類物件,就有點麻煩了。因為怕麻煩,所以就先寫個簡單的吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#import "view3.h" @interface view3 () @end @implementation view3 - (void)viewDidLoad { [super viewDidLoad]; UILabel *lable = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, 100, 50)]; lable.textColor = [UIColor blueColor]; lable.text =@"我是view3"; [self.view addSubview: lable]; UIButton *button = [[UIButton alloc] initWithFrame: CGRectMake(200, 200, 200, 200)]; [button setTitle: @"back" forState:UIControlStateNormal]; [button setTitleColor: [UIColor blackColor] forState:UIControlStateNormal]; [button addTarget: self action:@selector(back) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview: button]; } -(void) back { [self dismissViewControllerAnimated: YES completion:nil]; } -(void)iniViewControllerParam:(NSDictionary *)dic { self.title = [dic objectForKey: @"title"]; } |
說明:這個是要跳轉的頁面我們可以通過iniViewControllerParam:(NSDictionary *)dic
方法獲取上一個介面傳過來的引數。
說明:路由配置檔案,key:value的形式,頁面裡的每個跳轉動作都會對應一個唯一的key,這裡如果兩個頁面都跳轉到同一個頁面,就會產生不同的key 對應相同的value,感覺是有點冗餘了,如果有更好的優化,我會更新下文章的,這裡的配置檔案我們可以怎麼玩,由於我在android的這塊的描述已經很詳細了,所以這裡就不再贅述。只是android的配置有點坑,類前需要加上包名,這點就沒有iOS方便靈活了,至此iOS示例我就講完了。
下面讓我們來看下Android下的示例
Android平臺示例:
我們先看一下demo的結構
說明:example.mixu.wxrouter 路由使用示例
wx.router 路由管理檔案
assets 路由配置檔案
接下來,我們主要講解一下,wx.router裡面的檔案,以及assets配置檔案結構,還有MainActivity 檔案,其他的請下載示例demo,文末我會給出demo地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.example.mlxu.wxrouter; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import com.wx.router.Router; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.v("activity","activity:" + RouterUtil.getActivity(this, "MSG001")); Log.v("activity", "activity:" + RouterUtil.getActivity(this, "MSG002")); Log.v("activity", "activity:" + RouterUtil.getActivity(this, "MSG003")); } public void buttonClick(View v) { int id = v.getId(); switch (id) { case R.id.btn1: { startActivity(Router.initIntentWithActivityKey(this, "MSG001")); } break; case R.id.btn2: { startActivity(Router.initIntentWithActivityKey(this, "MSG002")); } break; case R.id.btn3: { Intent intent = Router.initIntentWithActivityKey(this, "MSG003"); intent.putExtra("url", "http://www.baidu.com"); startActivity(intent); } break; case R.id.btn4: { Intent intent = Router.initIntentWithActivityKey(this, "MSG005"); intent.putExtra("url", "http://www.baidu.com"); startActivity(intent); } break; } } } |
說明: 主要是呼叫Router.initIntentWithActivityKey(Context context, String key)
方法來獲取一個intent,這個intent裡面會根據你傳入的key去urlmap.json檔案中查詢對應的Activity,並設定好Intent要跳轉的class,獲取這個intent 後你只需要再設定一些跳轉需要傳的引數就可以了,為了提供最大的靈活性,我並沒有把跳轉引數,以及跳轉動作統一封裝在一塊,我們現在只做一個最簡單的路由跳轉,雖然簡單但我相信已經能夠實現我們絕大部分需求了,此處也參考過一些大神的路由,他們都是機遇url schema 的方式。有時還是感覺不太靈活,比如我要傳圖片物件,基與url 路徑的就不太好傳。有空再深入研究他們的實現細節吧,呵呵。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.wx.router; import android.content.Context; import android.content.Intent; public class Router { public static Class getActivityClassForName(Context context, String name) { Class clazz; try { clazz = Class.forName(name); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return clazz; } public static Intent initIntentWithActivityKey(Context context, String key) { Class clazz; String activityName = RouterUtil.getActivity(context, key); try { if ((activityName == "") || (activityName == null)) { clazz = RouterError.errorClass(context); } else { clazz = Class.forName(activityName); } } catch (ClassNotFoundException e) { // throw new RuntimeException(e); clazz = RouterError.errorClass(context); } Intent intent = new Intent(context, clazz); intent.putExtra("URLKEY", key); //??key?????????? return intent; } } |
說明:此處很簡單,就是通過把字串路徑轉換成class物件,然後通過Intent setClass(Context packageContext, Class> cls)
設定好要跳轉的 Activity.注意這行程式碼intent.putExtra("URLKEY", key);
這個我把每個跳轉頁面都傳入也一個引數,URLKey,就是我們配置檔案(urlmap.json)中的key,這個key是唯一的,為什麼設定這個引數,主要就是為了識別唯一的跳轉動作,假如我們這個頁面跳轉出錯了,我們讓它跳轉到一個統一的錯誤頁面,那麼我們根據URLKEY這個引數就能知道是哪個頁面跳轉出錯,該做什麼操作,我可以展示一個相應的錯誤頁面,或者跳轉到一個好的有相同功能的H5頁面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
package com.wx.router; import android.content.Context; import android.content.res.AssetManager; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class RouterUtil { private final static String fileName = "urlmap.json"; private static Map maplist; public static void initMaplistOfFile(Context context, String fileName) { if(maplist == null){ synchronized (RouterUtil.class){ if(maplist == null){ maplist = new HashMap(); StringBuffer sb = new StringBuffer(); AssetManager am = context.getAssets(); try { BufferedReader bf = new BufferedReader(new InputStreamReader(am.open(fileName))); String next = ""; while (null != (next = bf.readLine())){ sb.append(next); } }catch (IOException e){ e.printStackTrace(); sb.delete(0,sb.length()); } try { JSONArray jsonArray = new JSONArray(sb.toString().trim()); for(int i = 0; i keyIter= jsonObject.keys(); Map map = new HashMap(); String key; Object value; while (keyIter.hasNext()) { key = keyIter.next(); value = jsonObject.get(key); maplist.put(key, (String)value); } } } catch (JSONException e) { e.printStackTrace(); } } } } } public static String getActivity(Context context,String urlkey){ initMaplistOfFile(context, fileName); String value = ""; try { value = maplist.get(urlkey); }catch (Exception e){ value = ""; Log.w("UrlError",urlkey+"值不存在"); } return value; } } |
說明:路由讀取工具類,就是讀取urlmap.json檔案,並轉換成map,然後又提供一個根據key獲取value的方法,在獲取value時因為我們的配置檔案也不能保證格式都是正確的,難免開發中會寫錯,我們要做一些異常捕獲,並給出一些提示,我們有可能沒配置key,也有可能沒配置value,或者都沒配置,一方配置出錯,我們都無法例項化要跳轉的Activity.
1 2 3 4 5 6 7 |
package com.wx.router; import android.content.Context; public class RouterError { public static Class errorClass(Context context){ return Router.getActivityClassForName(context,RouterUtil.getActivity(context,"MSG003")); } } |
說明:路由錯誤類,如果配置檔案中沒配置相應的antivity,我們可以引導跳轉到一個統一的錯誤頁面。
1 |
[ {"MSG001":"com.example.mlxu.wxrouter.View1"}, {"MSG002":"com.example.mlxu.wxrouter.View2"}, {"MSG003":"com.example.mlxu.wxrouter.webview"}, {"MSG004":"com.example.mlxu.wxrouter.webview1"}] |
說明:路由配置檔案,是一個json檔案,裡面都是鍵值對 MSG001是key,後面就是相應的activity,key是唯一的,每一個頁面跳轉動作都對應一個Key,當然了這邊也有一個問題,當兩個頁面都跳轉到同一個頁面時,會出現重複的value.這個有時間再想下有沒有好的解決方法, 當然了這個配置檔案我們可以打包在app內,也可以從伺服器上拉取,或者兩者結合,配合版本控制,我們就能夠動態指定頁面跳轉路徑,比如說MSG001對應的頁面是個支付頁面,但是突然出現了大bug,支付不了了。那麼我們可以把MSG001改成一個我們統一的webview頁面,這個頁面中,我們可以讓它跳轉到我們線上臨時的H5頁面。這裡面我們可以讓所有發生錯誤的頁面,都跳轉到統一的webview,然後訪問同一個後臺介面,後臺根據我們傳的引數不同,然後引導跳轉到不同的線上H5頁面。
其實這裡面還有個可以改進的,我們可以優化[ {“MSG001″:”Native:com.example.mlxu.wxrouter.View1”}]
{“MSG001”:”web:http://www.baidu.com”}]
加個字首來識別自動跳轉原生頁面還是web頁面,等等,想想的空間還很多,好了android 的demo 到這裡也基本介紹完了。
總結:程式碼是簡陋的,只是簡單的實現了自己的構想,還有很多值得細細琢磨的地方,關鍵是架構思路,通過中間路由根據下發的路由配置檔案來動態跳轉頁面,解決原生開發的遇到的一些問題,不同的專案有不同的業務邏輯,這種思路有什麼缺陷,或者解決不了什麼問題,大家一起討論分享。基於這種思路搭建架子的話,對於將來的元件化開發,應該也會很方便轉換吧。?
demo地址
android:https://github.com/lerpo/WXAndroidRouter.git
iOS :https://github.com/lerpo/WXiOSRouter.git