摘要:前言學習也有一段時間了,關于在三端的使用,我們也做了實戰開發,渲染時間在之間,各平臺體驗相比都有極大的提升,此文章在的角度記錄開發過程中遇到的一些問題,如果想要了解前端和安卓的開發可以參考我同事寫的一些內容實踐前端視角實踐安卓視角準備工作
前言
weex學習也有一段時間了,關于weex在三端的使用,我們也做了實戰開發,渲染時間在100-300ms之間,各平臺體驗相比H5都有極大的提升,此文章在iOS的角度記錄開發過程中遇到的一些問題,如果想要了解前端和安卓的開發可以參考我同事寫的一些內容weex 實踐(前端視角)、weex 實踐(安卓視角)
準備工作weexSDK接入
Weex iOS SDK 官方集成指南
WXDevtool工具使用
Weex調試神器——Weex Devtools使用手冊
接下來我以訂單頁面為例,來描述一些用到的weex相關知識點,如下圖描述
1. 初始化SDK,注冊module、protocol、component
/* 在appDelagate里初始化weexSDK并注冊module、protocol、component */ -(void)initWeex{ /* 初始化SDK環境 */ [WXSDKEngine initSDKEnviroment]; /* 自定義module*/ [WXSDKEngine registerModule:@"shopBase" withClass:[BaseModule class]]; [WXSDKEngine registerModule:@"shopModal" withClass:[WXModuleAnno class]]; /* 初始化Protocol*/ [WXSDKEngine registerHandler:[WXImgLoaderDefaultImpl new] withProtocol:@protocol(WXImgLoaderProtocol)]; [WXSDKEngine registerHandler:[WXSJNetworkDefaultlmpl new] withProtocol:@protocol(WXNetworkProtocol)]; /* 初始化Component*/ [WXSDKEngine registerComponent:@"a" withClass:NSClassFromString(@"WXPushComponent")]; }
2. 實現類似選項卡的效果
如圖片第一點描述同一個viewcontroller多個view間的切換,此處本店訂單和我的訂單為不同的view,點擊來回切換,達到類似選項卡的效果
先貼段渲染weex頁面的基礎代碼
/*通過JS鏈接渲染weex頁面 會產出一個view*/ -(void)renderWeexWithUrl:(NSString *)url{ _instance = [[WXSDKInstance alloc] init]; _instance.viewController = self; CGFloat width = self.view.frame.size.width; _instance.frame = CGRectMake(self.view.frame.size.width-width, 0, width, _weexHeight); _instance.onCreate = ^(UIView *view) { /*頁面渲染成功 會產出一個view*/ }; _instance.onFailed = ^(NSError *error) { }; _instance.renderFinish = ^(UIView *view) { }; _instance.updateFinish = ^(UIView *view) { }; [_instance renderWithURL:[NSURL URLWithString:url] options:@{@"bundleUrl":url} data:nil]; }
如上所述 我們可以針對產出的view進行處理,簡單的頁面直接添加到self.view上即可。
假如需要多個view間的切換,就如訂單頁的tabbar切換,我這里做了如下處理:
把每次新產生的view存到一個字典里,key是鏈接 value是新產生view ,每次渲染頁面前先通過key查找是否已經存在該view,如果已存在把存的view拿出來展示,不存在渲染出來新的view
代碼修改如下
-(void)renderWeexWithUrl:(NSString *)url{ /*通過url查找是否已經存在該view 已存在顯示出來已有的 不再重新渲染*/ if ([self.mdicViews objectForKey:url] && [[self.mdicViews objectForKey:url] isKindOfClass:[UIView class]]) { [self loadViewforKey:url]; }else{ __weak typeof(self) weakSelf = self; _instance = [[WXSDKInstance alloc] init]; _instance.viewController = self; CGFloat width = self.view.frame.size.width; _instance.frame = CGRectMake(self.view.frame.size.width-width, 0, width, _weexHeight); _instance.onCreate = ^(UIView *view) { /*頁面渲染成功 會產出一個view*/ [weakSelf.mdicViews setValue:view forKey:url]; [weakSelf loadViewforKey:url]; }; _instance.onFailed = ^(NSError *error) { }; _instance.renderFinish = ^(UIView *view) { }; _instance.updateFinish = ^(UIView *view) { }; [_instance renderWithURL:[NSURL URLWithString:url] options:@{@"bundleUrl":url} data:nil]; } } /*通過key顯示某個view的操作*/ -(void)loadViewforKey:(NSString *)mstrJs{ self.weexView = [_mdicViews objectForKey:mstrJs]; [self.view insertSubview:self.weexView atIndex:0]; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.weexView); for (int i=0; i3. 自定義a標簽component 攔截url進行跳轉
#import@interface WXPushComponent : WXComponent @end #import "WXPushComponent.h" @interface WXPushComponent() @property (nonatomic, strong) UITapGestureRecognizer *tap; @property (nonatomic, strong) NSString *href; @end @implementation WXPushComponent - (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance { self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]; if (self) { _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openURL)]; _tap.delegate = self; if (attributes[@"href"]) { _href = attributes[@"href"]; } } return self; } - (void)dealloc { if (_tap.delegate) { _tap.delegate = nil; } } - (void)viewDidLoad { [self.view addGestureRecognizer:_tap]; } - (void)openURL { if (_href && [_href length] > 0) { /* a標簽的跳轉連接 可以根據該鏈接 進行跳轉 */ } } - (void)updateAttributes:(NSDictionary *)attributes { if (attributes[@"href"]) { _href = attributes[@"href"]; } } #pragma mark #pragma gesture delegate - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { return YES; } return NO; } @end 4. 自定義module實現confirm、toast、alert
#import#import #import @interface WXModuleAnno : NSObject @end #import "WXModuleAnno.h" @implementation WXModuleAnno @synthesize weexInstance; WX_EXPORT_METHOD(@selector(toast:)) WX_EXPORT_METHOD(@selector(alert:callback:)) WX_EXPORT_METHOD(@selector(confirm:callback:)) - (void)confirm:(NSDictionary *)param callback:(WXModuleCallback)callback { NSString *message = [self stringValue:param[@"message"]]; NSString *okTitle = [self stringValue:param[@"okTitle"]]; NSString *cancelTitle = [self stringValue:param[@"cancelTitle"]]; if (okTitle.length==0) { okTitle = @"確認"; } if (cancelTitle.length==0) { cancelTitle = @"取消"; } /* 此處為自己的彈框組件或者系統的組件 */ /**/ callback(okTitle); } - (void)toast:(NSDictionary *)param{ NSString *message = [NSString stringWithFormat:@"%@",param[@"message"]]; if (!message) return; /* 此處為自己的toast 組件 */ /**/ } - (void)alert:(NSDictionary *)param callback:(WXModuleCallback)callback { NSString *message = [self stringValue:param[@"message"]]; NSString *okTitle = [self stringValue:param[@"okTitle"]]; /* 此處為自己的彈框組件或者系統的組件 */ /**/ callback(okTitle); } // 獲取當前NVC -(UINavigationController *)currentNVC{ return [weexInstance.viewController navigationController]; } // 獲取當前VC -(UIViewController *)currentVC{ return weexInstance.viewController; } - (NSString*)stringValue:(id)value { if ([value isKindOfClass:[NSString class]]) { return value; } if ([value isKindOfClass:[NSNumber class]]) { return [value stringValue]; } return nil; } @end 5. 自定義圖片加載protocol,可以對圖片進行壓縮和緩存的處理
#import#import @interface WXImgLoaderDefaultImpl : NSObject @end #import "WXImgLoaderDefaultImpl.h" #import @interface WXImgLoaderDefaultImpl() @end @implementation WXImgLoaderDefaultImpl #pragma mark - #pragma mark WXImgLoaderProtocol - (id )downloadImageWithURL:(NSString *)url imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)userInfo completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock { if ([url hasPrefix:@"jpg"] || [url hasPrefix:@"png"]) { /* 做相應的處理 */ } return (id )[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:url] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (completedBlock) { completedBlock(image, error, finished); } }]; } @end 6. 自定義NetworkProtocol,可以針對網絡請求進行攔截修改
#importweex native webview 無縫跳轉#import @interface WXSJNetworkDefaultlmpl : NSObject @end #import "WXSJNetworkDefaultlmpl.h" @interface WXNetworkCallbackInfo : NSObject @property (nonatomic, copy) void(^sendDataCallback)(int64_t, int64_t); @property (nonatomic, copy) void(^responseCallback)(NSURLResponse *); @property (nonatomic, copy) void(^receiveDataCallback)(NSData *); @property (nonatomic, strong) NSMutableData *data; @property (nonatomic, copy) void(^compeletionCallback)(NSData *, NSError *); @end @implementation WXSJNetworkDefaultlmpl { NSMutableDictionary *_callbacks; NSURLSession *_session; } - (id)sendRequest:(NSURLRequest *)request withSendingData:(void (^)(int64_t, int64_t))sendDataCallback withResponse:(void (^)(NSURLResponse *))responseCallback withReceiveData:(void (^)(NSData *))receiveDataCallback withCompeletion:(void (^)(NSData *, NSError *))compeletionCallback { /*攔截了URL 如果沒有域名時 添加上域名 為了保持三端同步使用 我們域名放在每個端添加*/ if (![request.URL.absoluteString hasPrefix:@"http"]) { request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",@"",request.URL.absoluteString]]]; } WXNetworkCallbackInfo *info = [WXNetworkCallbackInfo new]; info.sendDataCallback = sendDataCallback; info.responseCallback = responseCallback; info.receiveDataCallback = receiveDataCallback; info.compeletionCallback = compeletionCallback; if (!_session) { _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; } NSURLSessionDataTask *task = [_session dataTaskWithRequest:request]; if (!_callbacks) { _callbacks = [NSMutableDictionary dictionary]; } [_callbacks setObject:info forKey:task]; [task resume]; return task; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { WXNetworkCallbackInfo *info = [_callbacks objectForKey:task]; if (info.sendDataCallback) { info.sendDataCallback(totalBytesSent, totalBytesExpectedToSend); } } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)task didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { WXNetworkCallbackInfo *info = [_callbacks objectForKey:task]; if (info.responseCallback) { info.responseCallback(response); } completionHandler(NSURLSessionResponseAllow); } - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)task didReceiveData:(NSData *)data { WXNetworkCallbackInfo *info = [_callbacks objectForKey:task]; if (info.receiveDataCallback) { info.receiveDataCallback(data); } NSMutableData *mutableData = info.data; if (!mutableData) { mutableData = [NSMutableData new]; info.data = mutableData; } [mutableData appendData:data]; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { WXNetworkCallbackInfo *info = [_callbacks objectForKey:task]; if (info.compeletionCallback) { info.compeletionCallback(info.data, error); } [_callbacks removeObjectForKey:task]; } @end 主要講解如何實現weex native webview間的跳轉,達到可以不僅隨意跳轉并且可以替換native頁面的效果
以下內容來源于我司安卓大神weex 實踐(安卓視角)
App的跳轉規則的weex支持方案設計
跳轉規則如下圖,如果看不清,可以到新頁面放大查看,主要介紹一下兩個配置參數:
1.參數interceptUrlList可以動態配置需要攔截的h5鏈接,然后生成統一跳轉地址 showjoyshop://page.sh/order
示例如下:[ { "page":"order", "url":"https://dshdjshjbx" }, { "page":"detail", "url":"https://dsdsds" } ]2.然后通過order在參數weexPages里查找對應的js信息,然后渲染
示例如下:[ { "page":"order", "url":"https://dshdjshjbx.js", "md5":"323827382huwhdjshdjs", "h5":"http://dsds.html" "v":"1.5.0" }, { "page":"detail", "url":"https://dsdsds.js", "md5":"323827382huwhdjshdjs", "h5":"http://dsds.html" "v":"1.5.0" } ]url: 需要渲染的js
md5: js文件的md5值用于校驗
h5: 渲染失敗后的降級方案
v: 最低支持的版本號
這樣就達到了動態攔截,動態上線weex的目的
預加載weex-JS頁面 提高渲染速度主要講解提前預下載JS文件的邏輯(當然也可以不預下載,直接使用js鏈接即可)
為了提升渲染效率,我們會提前把js文件下載到本地,使用時直接加載本地文件,下載邏輯如下:
首先我們會有一個地方錄入如下格式的json數據[ { "page":"頁面名稱", "url":"js下載鏈接", "md5":"js文件MD5", "h5":"對應的h5頁面" "v":"版本號" }, { "page":"shoporder", "url":"https://xxxx.js", "md5":"js文件MD5", "h5":"http://xxxx.html" "v":"1.7.0" } ]page: 對應統一跳轉的 path(暫為頁面名稱)
url: 需要渲染的js
md5: js文件的md5值用于校驗
h5: 渲染失敗后的降級方案
v: 最低支持的版本號
然后根據配置文件做如下操作
每次更新完配置文件,遍歷,查看是否存在md5一致的page_xxx.js文件,如果不存在則更新
下載完成后,保存格式為xxx.js,校驗md5
相同的話,記錄文件的最后修改時間
不同的話,刪除已下載文件,重新下載,重復校驗流程支持統一跳轉協議,page對應目前app端的統一跳轉協議里的page,有必要的時候可以替換原來的native頁面,解決native頁面錯誤不能及時修復的問題。加載失敗的話,打開h5頁面
每次打開指定頁面的時候,先檢查本地是否有對應page文件,再檢驗最后修改時間是否跟記錄的一致
一致就加載
不一致就用線上url第三條提到的統一跳轉協議是我們為了解耦各個模塊所使用的一種方式,可根據自己的業務做相應的改變 我們的就類似: showjoyshop://page.sh/weex showjoyshop://page.sh/webview weex對應的就是weex的vc webview對應的就是webview的vc weex和webview即是第三條提到的page
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86744.html
摘要:引入了新的環境和概要信息,是一種更揭秘與實戰六消息隊列篇掘金本文,講解如何集成,實現消息隊列。博客地址揭秘與實戰二數據緩存篇掘金本文,講解如何集成,實現緩存。 Spring Boot 揭秘與實戰(九) 應用監控篇 - HTTP 健康監控 - 掘金Health 信息是從 ApplicationContext 中所有的 HealthIndicator 的 Bean 中收集的, Spring...
摘要:大家好,我是冰河有句話叫做投資啥都不如投資自己的回報率高。馬上就十一國慶假期了,給小伙伴們分享下,從小白程序員到大廠高級技術專家我看過哪些技術類書籍。 大家好,我是...
閱讀 2746·2021-11-16 11:45
閱讀 1654·2021-09-26 10:19
閱讀 2051·2021-09-13 10:28
閱讀 2803·2021-09-08 10:46
閱讀 1530·2021-09-07 10:13
閱讀 1525·2019-08-30 13:50
閱讀 1374·2019-08-30 11:17
閱讀 1455·2019-08-29 13:18