《weex 實踐指北》第二章:客戶端接入 weex(iOS 視角)

vr266261 7年前發布 | 23K 次閱讀 Weex iOS開發 移動開發

對于你的“容器”而言,weex只是View層。

“請牢記上述的格言”,個人推薦大家在配置Cocoapods的時候,既要有weex團隊打包好的SDK,也要有引入源碼的準備。

pod 'WeexSDK', '0.9.4'
# pod 'WeexSDK', :path => '/User/icepy/weex/ios/sdk'

pod 'WXDevtool', '0.8.2'
# pod 'WXDevtool', :path => '/User/icepy/WXDevtool'

默認,你已經把環境準備完畢

初始化

既然weex只是View層,對于它接入,應該就比較簡單了。

參考: https://weex-project.io/doc/advanced/integrate-to-ios.html

參考: https://weex-project.io/doc/advanced/extend-to-ios.html

理論上,weex的初始化應該在App啟動時。但是,你也可以在特定的時候初始化weex。

[WXSDKEngine initSDKEnviroment];

當然,如果你需要有一點業務的配置,也可以使用 WXAppConfiguration ,因為這不是必須的。

[WXAppConfiguration setAppVersion:@""];
[WXAppConfiguration setAppName:@""];
[WXAppConfiguration setAppGroup:@""];

有時候日志信息,也是非常必要的,你可以使用 WXLog 來配置

[WXLog setLogLevel:WXLogLevelAll]

日志等級,有一組枚舉,你可以查看一下

typedef NS_ENUM(NSUInteger, WXLogLevel){
    /**
     *  No logs  沒有日志
     */
    WXLogLevelOff       = 0,

    /**
     *  Error only 僅僅是錯誤信息
     */
    WXLogLevelError     = WXLogFlagError,

    /**
     *  Error and warning  錯誤和警告
     */
    WXLogLevelWarning   = WXLogLevelError | WXLogFlagWarning,

    /**
     *  Error, warning and info  錯誤,警告,信息
     */
    WXLogLevelInfo      = WXLogLevelWarning | WXLogFlagInfo,

    /**
     *  Log, warning info  這里的log代表了js層面的console.log,可以在Xcode控制臺中可見
     */
    WXLogLevelLog       = WXLogFlagLog | WXLogLevelInfo,

    /**
     *  Error, warning, info and debug logs
     */
    WXLogLevelDebug     = WXLogLevelLog | WXLogFlagDebug,

    /**
     *  All
     */
    WXLogLevelAll       = NSUIntegerMax
};

完善你的ViewController

前言講到了weex只是一層View,那么將它和UIView劃等號也是可以的。在你的VC中,應該有一個URL的屬性,可以接到js bundle 文件。

- (instancetype)initWithURL:(NSURL *)url
{
    self = [super init];
    if (self) {
        _url = url;
    }
    return self;
}
@interface ViewController ()

@property(nonatomic, strong) WXSDKInstance *instance;
@property(nonatomic, strong) UIView *weexView;
@property(nonatomic, strong) NSURL *url;

@end

然后在 viewDidLoad 中進行初始化。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self render]
}

- (void) render {
    CGFloat width = self.view.frame.size.width;
    [self.instance destroyInstance];
    self.instance = [[WXSDKInstance alloc] init];
    self.instance.viewController = self;
    self.instance.frame = CGRectMake(self.view.frame.size.width - width, self.top, width, self.weexHeight);
    __weak typeof(self) weakSelf = self;
    self.instance.onCreate = ^(UIView *view){
        [weakSelf.weexView removeFromSuperview];
        weakSelf.weexView = view;
        [weakSelf.view addSubview:weakSelf.weexView];
        UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, weakSelf.weexView);
    };

    self.instance.onFailed = ^(NSError *error){
        NSLog(@"%@",error.userInfo);
    };

    self.instance.renderFinish = ^(UIView *view){
        [weakSelf.instance fireGlobalEvent:@"geolocation" params:@{@"key":@"value"}];
    };
    [self.instance renderWithURL:self.url options:nil data:nil];
}

從上述的邏輯來看,應該可以推敲出,weex 渲染結果雖然需要一個UIView來承接,最后再將這個UIView替換掉系統的view,所以理論上,你可以生成多個weex的instance,來拼湊頁面,只需要設置好frame即可。weex 在代碼層面上提供了幾個block,來讓你感知到渲染階段的幾個周期,比如是渲染錯誤了,還是渲染完成了,還是在渲染創建之前。

最后,別忘記了在 dealloc 里調用一下 destroyInstanc 來銷毀 weex 實例,不然會內存溢出。

-(void)dealloc{
    [self.instance destroyInstance];
}

到此,weex可以將你用web技術寫好的頁面,呈現在對應的View中。不過,一個應用如果都是純展示,那么到此就結束了,但往往不是。也許,你還需要各種各樣Native的能力,也許Native也需要各種各樣JS的能力。

且看看 weex 為我們提供了多少種方式。

JS Call Native

weex 提供了Module來讓JS主動Call Native,第一步你還是需要注冊你的 Module。

[WXSDKEngine registerModule:@"test-logger" withClass: [WXLoggerModule class]];
// WXLoggerModule.h

#import <Foundation/Foundation.h>
#import <WeexSDK/WXModuleProtocol.h>

@interface WXLoggerModule : NSObject <WXModuleProtocol>

@end
// WXLoggerModule.m

#import "WXLoggerModule.h"
#import <WeexSDK/WeexSDK.h>

@interface WXLoggerModule()

@end

@implementation WXLoggerModule

@synthesize weexInstance;

WX_EXPORT_METHOD(@selector(info:callback:));

- (void) info: (NSDictionary *) log callback:(WXKeepAliveCallback) callback{
    NSLog(@"WXLoggerModule ----> : %@",log);
    callback(@{@"success":@YES,@"address":@"beijing"},YES);
}


@end
// .js 文件
var logger = require('@weex-module/test-logger');
logger.info({name:"icepy"});

Native Call JS

目前來說Native主動去Call JS,還只能使用事件的方式。

var globalEvent = require('@weex-module/globalEvent');
globalEvent.addEventListener('nativecalljs',function (e){

});
self.instance.renderFinish = ^(UIView *view){
     [weakSelf.instance fireGlobalEvent:@"nativecalljs" params:@{@"name":@"icepy"}];
};

組件

從業務層面來說JS與Native可以互相通信,這是非常重要的一點,但是如果當前端有無法實現的或者很難實現的組件時,這個時候Component就派上用場了。

[WXSDKEngine registerComponent:@"test-image" withClass:[WXImageComponent class]];
//WXImageComponent.h

#import <WeexSDK/WeexSDK.h>

@interface WXImageComponent : WXComponent

@property(nonatomic, strong) NSString *imageSrc;

@end
//WXImageComponent.m

#import "WXImageComponent.h"

static CGFloat IMAGEWIDTH = 320;
static CGFloat IMAGEHEIGHT = 320;

@implementation WXImageComponent

-(instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
{
    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
        _imageSrc = [WXConvert NSString:attributes[@"src"]];
    }
    return self;
}

-(void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"DTWXImgaeCompnent ---- > %@",self.imageSrc);
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 20, IMAGEWIDTH, IMAGEHEIGHT)];
    imageView.userInteractionEnabled = YES;
    imageView.clipsToBounds = YES;
    imageView.exclusiveTouch = YES;
    imageView.contentMode = UIViewContentModeScaleToFill;
    NSURL *imageURL = [NSURL URLWithString:self.imageSrc];
    NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
    UIImage *image = [UIImage imageWithData:imageData];
    imageView.image = image;
    [self.view addSubview:imageView];
}

@end

使用起來就和使用Vue的組件類似

<test-image src=""></test-image>

其實,組件還有大量的生命周期,在這些生命周期內,你可以進行一些處理,總體來說,這是一個很有趣的事情。

 

 

 本文由用戶 vr266261 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!