移動端基于動態路由的架構設計

好久好久沒寫過文章了,一是最近項目太忙了,沒時間寫。二是也沒有時間學習新的東西,想寫點什么卻又無從下筆。最近在做混合App開發這塊,從開始的ionic 框架,到后來的mui框架,讓我在混合開發這塊有了更深的理解,等不太忙了,我想我會總結一篇這些框架的使用心得吧。但是我今天不講這個,我們來談一談在原生app中(iOS android)如何使用動態路由機制來搭建整個app的框架。
路由機制在web開發中是比較常見的,app開發中還是很少聽到這種概念的,目前有些大公司采用的組件化開發(手淘,攜程,蘑菇街等),倒是跟我們講的有很多相同之處,不過它們的比較復雜,而且網上很多組件化開發,路由機制,沒有一個能給出完整代碼示例的,看著讓人云里霧里的。索性自己就借鑒它們的思想,加上一點個人的理解,搞出了一個簡單實用的可行性demo出來。我們主要介紹以下三方面內容:

1 什么是動態路由
2 它能解決我們什么問題
3 如何在項目中實現

一 什么是動態路由

原生開發沒這概念,我們借助angular路由機制來解釋這一概念,所謂路由,就是一套路徑跳轉機制,事先通過配置文件定義好一個路徑映射文件,跳轉時根據key去找到具體頁面,當然angular會做一些緩存,頁面棧的管理等等一些操作,它大致的定義是這樣的

        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:'/'
                    })
            })
    </script>

config函數是一個配置函數。在使用
$routeProvider這樣的一個服務。when:代表當你訪問這個“/”根目錄的時候 去訪問 templateUrl中的那個模板。 controller可想已知,就是我們配套的controller,就是應用于根目錄的這個 模板時的controller。
ontherwise 就是當你路徑訪問錯誤時,找不到。最后跳到這個默認的 頁面。
為此我們可以總結一下幾個特點:
1 一個映射配置文件
2 路徑出錯處理機制
這就是路由的基本意思,我們看看,在原生開發中,采用此種方式,他能解決我們什么問題。


二 它能解決我們什么問題

首先我們來比較一下我們以前的結構模式以及與 加入路由機制后的項目結構,實現路由機制,不僅需要一個映射文件,還需要一套路由管理機制,那么采用路由機制,我們的項目架構就跟原來不一樣了,如下圖:

原先業務之間的調用關系.png
加入路由后的頁面調用關系.png

接下來我們看一下平時我們采用的頁面跳轉方法:
iOS 下
[self presentViewController:controller animated:YES completion:nil];
[self.navigationController pushViewController:controller animated:YES];

android 下

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結構

iOS demo結構圖.png

說明:WXRouter 路由管理文件
demo 路由使用示例
urlMap.plist 路由配置文件
我們主要講解一下 WXRouter里面的幾個文件,以及ViewController文件,還有urlmap.plist文件,其他請下載示例demo,文末我會給出demo地址。

WXRouter.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface WXRouter : NSObject
+(id)sharedInstance;
-(UIViewController *)getViewController:(NSString *)stringVCName;
-(UIViewController *)getViewController:(NSString *)stringVCName withParam:(NSDictionary *)paramdic;
@end
WXRouter.m
#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 方法來獲取傳過來的參數。

PlistReadUtil.h
#import <Foundation/Foundation.h>
@interface PlistReadUtil : NSObject
@property(nonatomic,strong) NSMutableDictionary *plistdata;
+(id)sharedInstanceWithFileName:(NSString *)plistfileName;
+(NSString *)plistValueForKey:(NSString *)key;
@end
PlistReadUtil.h
#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,或則訪問網絡獲取后臺服務器上的路由配置文件,這個根據我們業務需求的不同,可以添加不同的讀取方法。

RouterError.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface RouterError : NSObject
+(id)sharedInstance;
-(UIViewController *)getErrorController;
@end
RouterError.m
#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頁面。

ViewController.m
#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,這樣的路徑方式,但是個人感覺,如果界面之間傳遞圖片對象,或者傳嵌套的類對象,就有點麻煩了。因為怕麻煩,所以就先寫個簡單的吧。

view3.m
#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方法獲取上一個界面傳過來的參數。

urlMap.plist

說明:路由配置文件,key:value的形式,頁面里的每個跳轉動作都會對應一個唯一的key,這里如果兩個頁面都跳轉到同一個頁面,就會產生不同的key 對應相同的value,感覺是有點冗余了,如果有更好的優化,我會更新下文章的,這里的配置文件我們可以怎么玩,由于我在android的這塊的描述已經很詳細了,所以這里就不再贅述。只是android的配置有點坑,類前需要加上包名,這點就沒有iOS方便靈活了,至此iOS示例我就講完了。


下面讓我們來看下Android下的示例
Android平臺示例:

我們先看一下demo的結構

Paste_Image.png

說明:example.mixu.wxrouter 路由使用示例
wx.router 路由管理文件
assets 路由配置文件
接下來,我們主要講解一下,wx.router里面的文件,以及assets配置文件結構,還有MainActivity 文件,其他的請下載示例demo,文末我會給出demo地址。

#MainActivity.java
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 路徑的就不太好傳。有空再深入研究他們的實現細節吧,呵呵。

#Router.java
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頁面。

RouterUtil.java
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<String,String> 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 < jsonArray.length(); i++){
                            JSONObject jsonObject = (JSONObject)jsonArray.get(i);
                            Iterator<String> keyIter= jsonObject.keys();
                            Map<String,String> map = new HashMap<String,String>();
                            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.

RouterError.java
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,我們可以引導跳轉到一個統一的錯誤頁面。

urlmap.json
[  {"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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,242評論 25 708
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,915評論 18 139
  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,511評論 0 17
  • 前言 隨著用戶的需求越來越多,對App的用戶體驗也變的要求越來越高。為了更好的應對各種需求,開發人員從軟件工程的角...
    一縷殤流化隱半邊冰霜閱讀 87,447評論 214 1,098
  • 吃飯時無聊就思考了一個問題,一個關于餐飲行業的問題,下面我從背景和現象、分析與總結三個部分闡述一下我的思考。 思考...
    生椒牛肉閱讀 980評論 8 15