weex插件开发(iOS)

weex插件开发(iOS)

你应该要对照着这个教程来看本文。

假设你已经对weex开发有一定的了解,环境什么的都准备好了。

创建工程

执行下面命令可以创建一个weex插件开发工程:

$ weex plugin create dark-foo

实际上是weex-toolkit带来的便捷命令,归根结底是执行$ weexpack plugin create dark-foo,你可以替换着用。

会提示你please confirm iOS Project Name (DarkFoo),分别指定两端的项目名称,这里直接回车就行了。

在工程创建完后,weexpack会尝试自动运行npm的安装命令。如果失败,需要手动运行一下$ npm install,以便将需要的依赖都安装到工程中。

如果安装依赖的过程中有什么失败的话,挂上梯子再安装一次,3分钟搞定。

一切顺利的话,生成的插件工程目录文件结构如下:

├── android (Android插件工程目录)
│ ├── library (Android插件module目录,已被include到example工程中)
├── build
├── ios (ios插件工程)
├── js (h5插件工程)
├── examples (例子,开发者用来测试问题)
│ └── index.vue
├── node_modules (安装的依赖)
├── playground
│ ├── android (Android demo工程,集成了playground功能并默认引用了插件module)
│ ├── ios (demo,以pod的形式引用上面ios插件工程里面的源代码)
│ ├── browser (demo)
├── ****.podspec (ios的cocoapods发布文件)
├── start (native端weex编译命令)
├── start-web (浏览器端weex编译命令)
├── package.json (js发布文件)
├── README.md (插件发布到weex-market的时候显示的主页内容)

开始开发

作为一个iOS开发,这个时候你该关注的就只有index.vueplayground/ios了。

看见playground/ios下面的Podfile,首先当然是pod install(你喜欢pod update也行)安装工程所依赖的第三方库。

Podfile

如果你留意一下Podfile的内容,你会发现有这一句:

pod 'DarkFoo', :path=>'../../'

说明playground工程依赖了一个本地pod,这个本地pod就是我们插件工程目录DarkFoo.podspec文件描述的内容,这里简单地看这句:

s.source_files  = "ios/Sources/*.{h,m,mm}"

言简意赅,插件工程目录下的/ios/Sources里面的所有【.h .m .mm】文件都会被包含到这个pod里。

题外话说多了,让焦点回到WeexDemo.xcworkspace

开发流程

WeexDemo.xcworkspace跑起来之后,你会发现start同时也在终端跑起来了,这是weex跑起了环境,随时根据你的examples/index.vue代码变化而随时编译最新的前端页面,你可以在修改了index.vue之后点击界面右上角的刷新按钮来查看最新效果。

当然了,如果你改了iOS的原生代码,要在Xcode里重新Build,Run的。

现在我们把index.vue的代码改成如下这样:

<template>
<div class="conatiner">
<div class="conatiner">
<text style="margin-bottom: 20px;">weex plugin examples</text>
<text style="margin-top: 200px;">dark-foo plugin</text>
<div class="darkButton" @click="showAlert" ><text style="color:#fff">显示警告框</text></div>
<div class="darkButton" @click="dial" ><text style="color:#fff">拨号,异步获得结果</text></div>
<div class="darkButton" @click="something" ><text style="color:#fff">获取同步返回值</text></div>
</div>
</div>
</template>

<style>
.container{
flex: 1;
}
.darkButton{
margin: 20px;
padding:20px;
background-color:#1ba1e2;
color:#fff;
}
</style>

<script>
const plugin = weex.requireModule('darkFoo');
module.exports = {
data: {
value: '',
index: 0,
txtChange: ''
},
methods: {
showAlert: function() {
plugin.show();
},
dial: function() {

},
something: function() {

}
}
}
</script>
</script>

从来没有接触过vue.js,上面是仿我们前端同事写的,我们简单来看看代码。

template里的东西,大概可以理解为一个界面布局,style应该就是CSS咯,script应该就是JS。

这里放了三个长条,点击的时候执行@click指示的方法,我们可以看作是三个按钮,看看原生界面:

点击一下【显示警告框】,iOS模拟器就弹出UIAlertView了:

我们去iOS代码DarkFooModule类里看看写了些什么:

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

@interface DarkFooModule : NSObject<WXModuleProtocol>
@end


// ==================== .m ======================
#import "DarkFooModule.h"
#import <WeexPluginLoader/WeexPluginLoader.h>

@implementation DarkFooModule

WX_PlUGIN_EXPORT_MODULE(darkFoo, DarkFooModule)
WX_EXPORT_METHOD(@selector(show))

/**
create actionsheet

@param options items
@param callback
*/
-(void)show
{
UIAlertView *alertview = [[UIAlertView alloc] initWithTitle:@"title" message:@"module darkFoo is created sucessfully" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"ok", nil];
[alertview show];

}

@end

搭配官方文档-iOS扩展看一下就理解了,这里向weex暴露了一个module叫做DarkFooModule,并且暴露了show方法,用户点击weex界面的按钮时,vue的代码就会调用这个方法。

下面我们来把剩余两个按钮的方法补充完整,现在在iOS端的DarkFooModule.m里添加两个方法的代码:

/**
拨打电话
*/
- (void)call: (NSString *)phoneNumber callback:(WXModuleCallback)callback {
NSURL *url = [NSURL URLWithString: [@"tel:" stringByAppendingString:phoneNumber] ];
NSLog(@"%@", phoneNumber);
#if TARGET_OS_SIMULATOR
NSString *errMsg = @"模拟器不支持拨号!";
#else
NSString *errMsg = @"拨打的号码不正确!";
#endif
if (![[UIApplication sharedApplication] canOpenURL:url]) {
callback(@{
@"result": @"failed",
@"msg" : errMsg,
});
return;
}
if (@available(iOS 10, *)) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
if (success) {
callback(@{
@"result": @"success",
@"msg" : @"成功",
});
}
}];
} else {
[[UIApplication sharedApplication] openURL:url];
callback(@{
@"result": @"success",
@"msg" : @"成功",
});
}
}

- (NSString *) getSomething{
return @"哈哈";
}

照葫芦画瓢,把方法暴露给weex:

WX_EXPORT_METHOD(@selector(call:callback:))
WX_EXPORT_METHOD_SYNC(@selector(getSomething))

然后Xcode Build,Run没问题的话,我们再去写index.vue,把dialsomething改成这样:

dial: function() {
plugin.call("13800138000", function(ret){
console.log(ret.result);
console.log(ret.msg);
});
},
something: function() {
var s = plugin.getSomething();
console.log(s);
}

然后在iOS模拟器上刷新一下界面,再点击拨号按钮和同步返回值按钮,就能看到Xcode的控制台打印出console.log()函数的结果了:

既能同步又能异步,参数互传(我只看到字符串,估计用JSON来交换数据就好了)也能实现,那就能发挥想象,为所欲为啦!

本地集成

插件测试好之后,怎么把它集成到我们真正的weex工程里呢?

如果你是想发布到weex-market,看文章最开头的插件教程链接就行啦,下面来看看如何本地集成。

插件描述文件

你需要参考这里,写一个plugin.xml并且放到插件工程根目录下。
iOS插件的格式可以参考这个plugin.xml

理论上这个文件应该是由$ weex plugin create dark-foo命令顺便生成的,但是不知道为什么就是没有。可能是的新版weexpack创建的插件不含有此文件。

我们的dark-foo插件按照上面链接的文档,写出的xml应该是这个样子的:

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://www.w3.org/ns/widgets"
id="dark-foo"
version="0.0.1">
<name>dark-foo</name>
<description>weex-plugin-ios-test</description>
<license>Apache 2.0</license>
<keywords>weex,plugin</keywords>
<repo>https://*.git</repo>
<issue>https://*</issue>
<!-- ios -->
<platform name="ios">
<config-file target="WeexpluginConfig.xml" parent="/*">
<feature name="DarkFooModule">
<param name="category" value="module" />
<param name="ios-package" value="DarkFooModule" />
<param name="api" value="darkFoo" />
</feature>
</config-file>
<header-file src="ios/Sources/DarkFooModule.h" />
<source-file src="ios/Sources/DarkFooModule.m" />

</platform>

<!-- android -->

</plugin>

添加本地插件到weex工程

我们在你实际的weex项目里添加一个ios的测试项目先(已有就别添加啦):

$ weex platform add ios

添加本地插件需要执行:

$ weex plugin add /Users/darkhandz/Desktop/dark-foo

add后面就是你的插件工程本地目录啦,但是要注意下,把插件目录用作测试环境依赖的node_modules文件夹删除掉。


如果缺少了上述的plugin.xml文件,你尝试本地集成dark-foo插件的话,weex会提示:

Error: Cannot find plugin.xml for plugin "dark-foo". Please try adding it again.

如果是把写好的插件发布到市场再在本地安装这个上了市场的插件,是没问题的,但是本地直接安装就有问题。


还要注意的是,我们的这个dark-foo插件目前只支持iOS(plugin.xml里没写Android相关的内容),所以你的weex工程里不要有Android这个platform,不然铁定报错:

Installing "dark-foo@0.0.1" for android
Failed to install 'dark-foo':Error: ENOENT: no such file or directory, open '/Users/darkhandz/Documents/YunshengPark_weex/platforms/android/AndroidManifest.xml'

插件安装完成的话,你可以在你的weex项目里的plugins目录下看到dark-foo,也可以用命令来查看已安装的插件:

$ weex plugin list

想删除已安装的本地插件的话,用下面的命令似乎不可以,命令总是去线上找这个插件……

$ weex plugin remove dark-foo

这个时候只能手动删除了,在weex项目目录下的plugins目录,fetch.jsonios.json都有dark-foo插件相关的信息,自己手动删除一下吧,还有node_modules文件夹里面的dark-foo也要删除。

集成后测试

在你的weex工程里的某个vue写上我们的界面代码,然后build出来对应的js,然后在iOS测试项目(platfrom/ios)的WeexSDK里加载这个js,就会显示vue对应的界面了。

都是weex的基本操作,就不展开细说了。

测试用到的npm命令:

"buildios": "npm run build && rm -rf ./platforms/ios/bundlejs && cp -r ./dist/ ./platforms/ios/bundlejs/ && cp ./dist/native/views/test.js ./platforms/ios/bundlejs/index.js"