媒介
weex进修也有一段时刻了,关于weex在三端的运用,我们也做了实战开辟,衬着时刻在100-300ms之间,各平台体验比拟H5都有极大的提拔,此文章在iOS的角度纪录开辟过程当中碰到的一些题目,如果想要相识前端和安卓的开辟能够参考我同事写的一些内容weex 实践(前端视角)、weex 实践(安卓视角)
准备工作
weexSDK接入
Weex iOS SDK 官方集成指南WXDevtool东西运用
Weex调试神器——Weex Devtools运用手册
定单页实战(weex-iOS相干)
接下来我以定单页面为例,来形貌一些用到的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; i<self.view.subviews.count; i++) {
UIView * mview = [self.view.subviews objectAtIndex:i];
if (i==0) {
mview.hidden=NO;
}else{
mview.hidden=YES;
}
}
}
3. 自定义a标签component 阻拦url举行跳转
#import <WeexSDK/WXComponent.h>
@interface WXPushComponent : WXComponent <UIGestureRecognizerDelegate>
@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 <Foundation/Foundation.h>
#import <WeexSDK/WXModuleProtocol.h>
#import <WeexSDK/WeexSDK.h>
@interface WXModuleAnno : NSObject<WXModuleProtocol>
@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 <Foundation/Foundation.h>
#import <WeexSDK/WXImgLoaderProtocol.h>
@interface WXImgLoaderDefaultImpl : NSObject<WXImgLoaderProtocol>
@end
#import "WXImgLoaderDefaultImpl.h"
#import <SDWebImage/UIImageView+WebCache.h>
@interface WXImgLoaderDefaultImpl()
@end
@implementation WXImgLoaderDefaultImpl
#pragma mark -
#pragma mark WXImgLoaderProtocol
- (id<WXImageOperationProtocol>)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<WXImageOperationProtocol>)[[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,能够针对收集要求举行阻拦修正
#import <Foundation/Foundation.h>
#import <WeexSDK/WeexSDK.h>
@interface WXSJNetworkDefaultlmpl : NSObject<WXNetworkProtocol, NSURLSessionDelegate>
@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 无缝跳转
重要解说怎样完成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