iOS下JS与OC互相调用(八)--Cordova简单实战
新建工程,添加Cordova 关键类
新建一个工程TestCordova 然后添加:confug.xml、Private 和 Public 两个文件夹里的所有文件
然后build 发现报错
原因是Cordova 部分类中,并没有
#import <Foundation/Foundation.h>
,但是它们却使用了这个库里的NSArray、NSString 等类型。为什么用在终端里用命令行创建的工程就正常呢?
那是因为用命令行创建的工程里已经包含了pch 文件,并且已经import 了 Foundation框架。截图为证:
#import <Cordova/CDV.h>
,但是我们现在是直接在目标工程里添加Cordova,所以要把#import <Cordova/CDV.h>
改为 #import "CDV.h"
。其他的文件引用报错同理(比如:#import <Cordova/CDVCommandDelegate.h>会报错 只需改为 #import "CDVCommandDelegate.h"即可)。设置控制器,添加WebView
加载本地HTML,为了方便起见,首先新建一个叫
www
的文件夹,然后在文件夹里放入要加载的HTML和cordova.js
。这里把
www
添加进工程时,需要注意勾选的是create foler references,创建的是蓝色文件夹:<feature name="TestPlugin"> <param name="ios-package" value="TestPlugin" /> </feature> <feature name="LocalStorage"> <param name="ios-package" value="CDVLocalStorage" /> </feature> <feature name="HandleOpenUrl"> <param name="ios-package" value="CDVHandleOpenURL" /> <param name="onload" value="true" /> </feature> <feature name="IntentAndNavigationFilter"> <param name="ios-package" value="CDVIntentAndNavigationFilter" /> <param name="onload" value="true" /> </feature> <feature name="GestureHandler"> <param name="ios-package" value="CDVGestureHandler" /> <param name="onload" value="true" /> </feature>
下面我再截图看下:
OK,可以运行项目了:
2.加载远程HTML
项目里一般都是这种情况,接口返回H5地址,然后用网页加载H5地址。
只需要设置下 self.startPage
就好了。
这里有几个需要注意的地方: 1:self.startPage的赋值,必须在[super viewDidLoad]之前,否则self.startPage 会被默认赋值为index.html。 2:需要在config.xml中修改一下配置,否则加载远程H5时,会自动打开浏览器加载, 需要添加的配置是: <allow-navigation href="https://*/*" /> <allow-navigation href="http://*/*" /> 3:远程H5中也要引用cordova.js文件。 4:在 info.plist 中添加 App Transport Security Setting的设置。
创建插件,配置插件
在插件中实现JS要调用的原生方法,插件要继承自CDVPlugin
,示例代码如下:
// // TestPlugin.h // TestCordova // // Created by Doman on 2017/7/14. // Copyright © 2017年 Doman. All rights reserved. // #import "CDV.h" @interface TestPlugin :CDVPlugin - (void)scan:(CDVInvokedUrlCommand *)command; - (void)location:(CDVInvokedUrlCommand *)command; - (void)pay:(CDVInvokedUrlCommand *)command; - (void)share:(CDVInvokedUrlCommand *)command; - (void)changeColor:(CDVInvokedUrlCommand *)command; - (void)testController:(CDVInvokedUrlCommand*)command; @end
配置插件,是在config.xml的widget
中添加自己创建的插件,上面已经提到过。
如下图所示:
关于插件中方法的实现有几个注意点:
如果你发现类似如下的警告:
THREAD WARNING: ['scan'] took '290.006104' ms. Plugin should use a background thread.
那么直需要将实现改为如下方式即可:
[self.commandDelegate runInBackground:^{ // 这里是实现 }];
演示代码:
- (void)scan:(CDVInvokedUrlCommand *)command { [self.commandDelegate runInBackground:^{ dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"原生弹窗" message:nil delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]; [alertView show]; }); }]; }
如何获取JS 传过来的参数呢?CDVInvokedUrlCommand
参数,其实有四个属性,分别是arguments
、callbackId
、className
、methodName
。其中arguments
,就是参数数组。
看一个获取参数的示例代码:
- (void)share:(CDVInvokedUrlCommand *)command { NSUInteger code = 1; NSString *tip = @"分享成功"; NSArray *arguments = command.arguments; if (arguments.count < 3) {; code = 2; tip = @"参数错误"; NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@')",tip]; [self.commandDelegate evalJs:jsStr]; return; } NSLog(@"从H5获取的分享参数:%@",arguments); NSString *title = arguments[0]; NSString *content = arguments[1]; NSString *url = arguments[2]; // 这里是分享的相关代码...... // 将分享结果返回给js NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; [self.commandDelegate evalJs:jsStr]; }
如何将Native的结果回调给JS ?
这里有两种方式:第一种是直接执行JS,调用UIWebView 的执行js 方法。示例代码如下:
// 将分享结果返回给js NSString *jsStr = [NSString stringWithFormat:@"shareResult('%@','%@','%@')",title,content,url]; [self.commandDelegate evalJs:jsStr];
CDVPluginResult
和API。使用这种方式时,在JS 调用原生功能时,必须设置执行成功的回调和执行失败的回调。即设置
cordova.exec(successCallback, failCallback, service, action, actionArgs)
的第一个参数和第二个参数。像这样:function locationClick() { cordova.exec(setLocation,locationError,"HaleyPlugin","location",[]); }
然后,Native 调用JS 的示例代码:
- (void)location:(CDVInvokedUrlCommand *)command { // 获取定位信息...... // 下一行代码以后可以删除 // NSString *locationStr = @"广东省深圳市南山区学府路XXXX号"; NSString *locationStr = @"错误信息"; // NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')",locationStr]; // [self.commandDelegate evalJs:jsStr]; [self.commandDelegate runInBackground:^{ CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:locationStr]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; }]; }
上面大家已经看到,插件类要继承CDVPlugin ,点进去看下:
有个viewController,所以我门可以直接用.
演示代码:
- (void)testController:(CDVInvokedUrlCommand*)command { if (command.arguments.count>0) { //customize argument TestViewController* testViewCtrl = [[TestViewController alloc]init]; [self.viewController presentViewController:testViewCtrl animated:YES completion:^{ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"我是OC回传的参数!"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; }]; }else{ //callback CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"没有参数"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } }
JS 要调用原生,执行的是:
// successCallback : 成功的回调方法 // failCallback : 失败的回调方法 // server : 所要请求的服务名字,就是插件类的名字 // action : 所要请求的服务具体操作,其实就是Native 的方法名,字符串。 // actionArgs : 请求操作所带的参数,这是个数组。 cordova.exec(successCallback, failCallback, service, action, actionArgs);
Native 调用 JS 方法
这个非常简单,如果是在控制器中,那么只需要像如下这样既可:
- (void)testClick { NSString *jsStr = @"asyncAlert('哈哈啊哈')"; [self.commandDelegate evalJs:jsStr]; }
这里的evalJs
内部调用的其实是 UIWebView
的 stringByEvaluatingJavaScriptFromString
方法。
OK。到这里就结束了。
demo地址: https://github.com/domanc/TestCordova.git