Swift 中的 weex
weex ios 集成
参阅:Weex学习与实践:iOS原理篇
swift集成weex
首先将weexsdk集成到项目中,同OC
将weex的WeexSDK.framework导入
![](https://img.haomeiwen.com/i1830761/acedb6520d6528ff.png)
将main.js导入项目中。main.js在weex的WeexSDK.framework中
![](https://img.haomeiwen.com/i1830761/ccb1b7524245ffdd.png)
swift 使用weex
1、初始化weex和调用
import WeexSDK
AppDelegate.Swift中
WXAppConfiguration.setAppGroup("SwiftWeexSample")
WXAppConfiguration.setAppName("SwiftWeexSample")
WXAppConfiguration.setAppVersion("1.0.0")
WXLog.setLogLevel(WXLogLevel.All)
//init WeexSDK
WXSDKEngine.initSDKEnviroment()
ViewController.Swift中
//
// ViewController.swift
// SwiftWeexSample
//
// Created by zifan.zx on 6/18/16.
// Copyright © 2016 com.taobao.weex. All rights reserved.
//
import UIKit
import WeexSDK
class ViewController: UIViewController {
var instance:WXSDKInstance?;
var weexView = UIView()
var weexHeight:CGFloat?;
var top:CGFloat?;
var url:NSURL?;
override func viewDidLoad() {
super.viewDidLoad()
if !self.navigationController!.navigationBar.hidden {
top = CGRectGetMaxY(self.navigationController!.navigationBar.frame);
} else {
top = CGRectGetMaxY(UIApplication.sharedApplication().statusBarFrame)
}
weexHeight = self.view.frame.size.height - top!;
render()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
deinit {
if instance != nil {
instance!.destroyInstance()
}
}
func render(){
if instance != nil {
instance!.destroyInstance()
}
instance = WXSDKInstance();
instance!.viewController = self
let width = self.view.frame.size.width
instance!.frame = CGRectMake(self.view.frame.size.width-width, top!, width, weexHeight!)
weak var weakSelf:ViewController? = self
instance!.onCreate = {
(view:UIView!)-> Void in
weakSelf!.weexView.removeFromSuperview()
weakSelf!.weexView = view;
weakSelf!.view.addSubview(self.weexView)
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, weakSelf!.weexView)
}
instance!.onFailed = {
(error:NSError!)-> Void in
print("faild at error: %@", error)
}
instance!.renderFinish = {
(view:UIView!)-> Void in
print("render finish")
}
instance!.updateFinish = {
(view:UIView!)-> Void in
print("update finish")
}
instance!.renderWithURL(url, options: ["bundleUrl":String.init(format: "file://%@/bundlejs/", NSBundle.mainBundle().bundlePath)], data: nil)
}
}
2、module 扩展,自定义模块
有些时候我们希望JS层面能够调用Native的一些功能,比如通过JS代码让Native打开一个特定的url。这时候,我们可以自定义一个模块向JS层面暴露API:
因为module
暴露method
是通过 Objective-C
宏来做的,调用的时候是通过反射,所以Swift
扩展module
通过extension Objective-C
的类,以下操作,可以直接在weex 的iOS playground
中进行
1、拓展module
新建WXSwiftTestModule.h/m
和 WXSwiftTestModule.swift
文件, 在新建Swift文件的时候会提示
![](https://img.haomeiwen.com/i1830761/22d398e8140e5bdf.jpg)
选择 Create Bridging Header
, 因为我们要在swift中访问Objective-C
的一些类,正是通过这个header暴露OC的类给Swift,header格式为 yourTarget-Bridging-Header.h
,我这里创建完header文件名称为:WeexDemo-Bridging-Header.h
WXSwiftTestModule.h/m 中实现
WXSwiftTestModule.m 中
/**
* Created by Weex.
* Copyright (c) 2016, Alibaba, Inc. All rights reserved.
*
* This source code is licensed under the Apache Licence 2.0.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <WeexSDK/WeexSDK.h>
@interface WXEventModule : NSObject <WXModuleProtocol>
@end
WXSwiftTestModule.m 中
WeexDemo-Swift.h 这个文件需要编译一下才可以搜索到,具体的路径
/**
* Created by Weex.
* Copyright (c) 2016, Alibaba, Inc. All rights reserved.
*
* This source code is licensed under the Apache Licence 2.0.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
#import "WXEventModule.h"
#import "SwiftWeexSample-Bridging-Header.h"
@implementation WXEventModule
@synthesize weexInstance;
WX_EXPORT_METHOD(@selector(openURL:))
@end
Swift 中实现
- 扩展 OC的类 WXSwiftTestModule ,增加了一个方法,这个方法就是我们要暴露出来,在js中可以调到的
//
// WXEventModule.swift
// SwiftWeexSample
//
// Created by zifan.zx on 24/09/2016.
// Copyright © 2016 com.taobao.weex. All rights reserved.
//
import Foundation
public extension WXEventModule {
public func openURL(url:String) {
var newUrl:String = url;
if url.hasPrefix("//") {
newUrl = String.init(format: "http://%@", url);
}else if !url.hasPrefix("http") {
//relative path
newUrl = (NSURL.init(string: url, relativeToURL: weexInstance.scriptURL)!.absoluteString)!
}
let controller:ViewController = ViewController()
controller.url = NSURL.init(string: newUrl)
weexInstance.viewController.navigationController?.pushViewController(controller, animated:true)
}
}
如果需要调用oc的类,需要在SwiftWeexSample-Bridging-Header
中暴露。
至此这个Swift的简单的module 已经算是开发完成
注意点如下:
- 需要遵循WXModuleProtocol协议;
- 需要合成(synthesize)weexInstance属性;
- 使用WX_EXPORT_METHOD来暴露API;
- 使用WXModuleCallback进行回调;
2、module 使用
1、在注册weex时,注册module
// register event module
WXSDKEngine.registerModule("event", withClass: NSClassFromString("WXEventModule"))
2、we 文件中使用
<template>
<text>Swift Module</text>
</template>
<script>
require('weex-components');
Module.exports = {
data:{
},
ready: function(){
var swifter = require('@weex-module/swifter');
swifter.openURL('http://baidu.com');
};
}
</script>
3、下载图片
weex中没有直接下载图片的方法,所以需要进行以下操作。
在项目中,导入SDWebImage
新建WXImgLoaderDefaultImpl.h/m
文件,在.h文件中
/**
* Created by Weex.
* Copyright (c) 2016, Alibaba, Inc. All rights reserved.
*
* This source code is licensed under the Apache Licence 2.0.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <WeexSDK/WeexSDK.h>
@interface WXImgLoaderDefaultImpl : NSObject<WXImgLoaderProtocol, WXModuleProtocol>
@end
.m文件中
/**
* Created by Weex.
* Copyright (c) 2016, Alibaba, Inc. All rights reserved.
*
* This source code is licensed under the Apache Licence 2.0.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
#import "WXImgLoaderDefaultImpl.h"
#import "SDWebImageManager.h"
#define MIN_IMAGE_WIDTH 36
#define MIN_IMAGE_HEIGHT 36
#if OS_OBJECT_USE_OBJC
#undef WXDispatchQueueRelease
#undef WXDispatchQueueSetterSementics
#define WXDispatchQueueRelease(q)
#define WXDispatchQueueSetterSementics strong
#else
#undef WXDispatchQueueRelease
#undef WXDispatchQueueSetterSementics
#define WXDispatchQueueRelease(q) (dispatch_release(q))
#define WXDispatchQueueSetterSementics assign
#endif
@interface WXImgLoaderDefaultImpl()
@property (WXDispatchQueueSetterSementics, nonatomic) dispatch_queue_t ioQueue;
@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:@"//"]) {
url = [@"http:" stringByAppendingString:url];
}
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
然后再注册weex时,注册handler
// register handler
WXSDKEngine.registerHandler(WXImgLoaderDefaultImpl(), withProtocol:NSProtocolFromString("WXImgLoaderProtocol"))
4、自定义UI组件
如果Weex的内置标签不足以满足要求时,我们可以自定义Native组件,然后暴露给.we文件使用。
比如我们可以定义一个WXButton
,继承自WXComponent
,
1.创建UI组件WXButton,继承自WXComponent
WXButton.h中
//
// WXButton.h
// LSWeexSwiftDemo
//
// Created by John_LS on 2016/11/15.
// Copyright © 2016年 John_LS. All rights reserved.
//
#import <WeexSDK/WeexSDK.h>
@interface WXButton : WXComponent
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIButton *innerButton;
@end
在WXButton.m中
//
// WXButton.m
// LSWeexSwiftDemo
//
// Created by John_LS on 2016/11/15.
// Copyright © 2016年 John_LS. All rights reserved.
//
#import "WXButton.h"
@implementation WXButton
-(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) {
self.title = [WXConvert NSString:attributes[@"title"]];
}
return self;
}
-(void)viewDidLoad{
[super viewDidLoad];
self.innerButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.innerButton.frame = self.view.bounds;
[self.view addSubview:self.innerButton];
[self.innerButton setTitle:self.title forState:UIControlStateNormal];
[self.innerButton addTarget:self action:@selector(onButtonClick:)
forControlEvents:UIControlEventTouchUpInside];
}
-(void)onButtonClick:(UIButton*)btn{
NSLog(@"按钮被onButtonClick击了");
}
@end
其中,在
-(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) {
self.title = [WXConvert NSString:attributes[@"title"]];
}
return self;
}
方法中可以获得we文件标签里面的属性,如title,通过这些属性,我们可以在组件生命周期中修改组件的样式,比如上面已经设置了按钮的title。
2、然后将其注册进Weex SDK:
// register component
WXSDKEngine.registerComponent("weex-button", with: NSClassFromString("WXButton"))
3、在we文件中调用按钮标签
<template>
<div>
<image class="thumbnail" src="http://image.coolapk.com/apk_logo/2015/0817/257251_1439790718_385.png"></image>
<text class="title" onclick="onClickTitle">Hello Weex</text>
<weex-button class="button" title="hello button" ></weex-button>
</div>
</template>
<style>
.title { color: red; }
.thumbnail { width: 100; height: 100; }
.button { color: blue; width: 100; height: 100;}
</style>
<script>
module.exports = {
methods: {
onClickTitle: function (e) {
console.log(e);
alert('title clicked.');
}
}
}
</script>
注:we文件中按钮的标签要与注册weexSDK时填写的字符串一致。