项目组准备开发一个APP,要求Android和iOS端页面彻底一致,除了一个页面跟业务相关的不一样,其余界面基本一致,所以,萌生一个想法,关于webAPP的想法。因而乎苦逼的咱们开始调研可行性以及总体的方案流程。为了达到除了业务数据页面用web,其余页面全是原生APP的做用。其中,关于业务的web页面须要调用原生的相机,相册,地理位置,麦克风,扬声器,扫描二维码等一系列功能,这就涉及到js与原生交互的问题了。
咱们iOS端提出的方案是直接用WebView或者用WKWebView嵌套在实现web与原生的交互就能够了,不过安卓同事说安卓由于其平台多样性和特殊性这个就不兼容并且可行性交差,列出了集中方案,最终肯定双方都用Cordova实现该功能。而后,开始了iOS端关于Cordova的学习之路(若是已经集成,请下翻到5节)javascript
Cordova前身是phonegap,而PhoneGap是Nitobi软件公司2008年推出的一个框架,旨在弥补web和iOS之间的不足,使得web和iPhone SDK之间的交互更容易。后来又加入了Android SDK 和BlackBerry SDK,再而后又陆续加入了更多的平台。可是在2011年,Nitobi公司被Adobe收购,PhoneGap也被提交到Apache Incubator。因为Adobe如今拥有PhoneGap商标,PhoneGap v2.0版产品就改名为Apache Cordova。css
听说Cordova是Nitobi团队当时坐落的街道名称,用此名来记念Nitobi团队的贡献。Apache Cordova是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎。html
有下图能够看出,关于Cordova的工程结构以及与Native API之间的关系:java
由上图能够看出,其实Cordova的使用分为上面几个框架结构,在Native与web之间交互。node
由于本人从事iOS工做,因此只阐述在Mac端安装Cordova的步骤及解释,至于windows下安装Cordova的步骤,这里再也不赘述。
(1)首先,你要有一台Mac电脑,若是没有,那么,你就把这篇文章关了吧,看了也没什么用。
(2)而后你须要安装xcode,固然,你要开发,这一点必不可少。
(3)你须要申请证书,而后在xcode中设置配置文件开发者帐号...(可后面再作)。
(4)好了,你能够开始安装Cordova了。jquery
要安装Cordova,须要先安装Node.js在Node.js官网,上下载并安装,下载好之后,一步一步点击下去就好。若是你实在不会,能够参考文章Mac下安装Node.js。linux
git通常不用安装,osx和linux都自带git,能够在命令行输入git --version
检查一下。若是没有git,须要到git官网下载安装一个git客户端。ios
接下来,在终端输入命令:git
sudo npm install -g cordova
过程可能稍微有点枯燥和漫长,请耐心等待,其实须要输入的安装命令只有npm install -g cordova,之因此输入sodu,是由于有点Mac直接输入前一句代码是安装不起的,安装效果以下图:
为了写文章因此第二次安装,第一次安装的效果不记得了,哈哈~github
继续,打开终端,cmd切换目录到工做目录下,输入如下命令,一样,可能须要点时间来完成
cordova create Demo com.cordova.demo.hello HelloWorld
参数描述:
Demo(参数是必填):将为你的项目生成一个Demo目录 www子目录是应用程序的主页,以及各类资源(css,js,img),遵循共同的web开发文件命名规范。这些资源将存储在设备上的本地文件系统,而不是远程服务。config.xml文件包含重要的须要生成和分发应用程序的元数据。
com.cordova.demo.hello(参数可选):App ID,若是不填写这个参数,第三个参数就要省略,默认值是 io.cordova.hellocordova,但建议你填写一个适当的值。
HelloWorld(参数可选):应用程序的项目名 这个参数的默认值是 HelloCordova,但建议你填写一个适当的值。
全部后续命令在项目的目录中进行,可在该项目任何子目录中,cmd切换到项目目录下:
cd Demo
在构建项目以前,你须要指定一组目标平台。你可以运行这些命令取决于您的机器是否支持每个SDK,合理是否已安装SDK。在MAC上运行命令:
cordova platform add ios
若是须要查看Cordova支持平台以及已经添加的平台,终端输入命令:
cordova platforms ls
根据项目具体功能须要,可添加插件以简单方便调用原生接口,如需添加插件,能够去Cordova插件库搜索须要的插件:
cordova plugin add com.phonegap.plugins.barcodescanner cordova plugin add org.apache.cordova.file-transfer cordova plugin ls
并不是全部的插件都是全平台支持的,有些可能只支持安卓,也有的可能同时支持安卓和iOS,因此在多平台开发时,请慎重选择插件。我的建议,可自定义插件类,可参考官网Cordova自定义插件。
// 在工程目录下运行下面的命令来构建项目: cordova build // 或者,指定生成iOS平台代码项目: cordova platform add iosiOS_Cordova
步骤走完第三章,那么,一个简单的Cordova项目就已经搭建完成了,如今,咱们运行下咱们工程。打开目录下
/Users/****/Desktop/测试cordova/Demo/platforms/ios
为了不引发混淆,建议移除掉下图中两个文件/文件夹引用(应用哦):
Cordova生命周期事件
生命周期函数 | 释义 |
---|---|
deviceready | 当Cordova加载完成会触发 |
pause | 当应用程序进入到后台时触发 |
resume | 应用程序从后台进入到前台会触发 |
这里看Api就能够的。
到此cordova环境的搭建集成基本完成了。有一些项目已经完成了忽然要集成cordova,该怎么办呢?往下看。
首先,进入到上一篇文章中建立的Cordova项目的路径中/Users/****/Desktop/Demo/platforms/ios,找到下面须要copy的4个文件夹( CordovaLib ,cordova, www, platform_www
)copy到工程项目的根路径中,以下
而后将下面图中所示的config.xml文件copy到须要的iOS项目路径文件夹内,如图:
NODEJS_PATH=/usr/local/bin; NVM_NODE_PATH=~/.nvm/versions/node/`nvm version 2>/dev/null`/bin; N_NODE_PATH=`find /usr/local/n/versions/node/* -maxdepth 0 -type d 2>/dev/null | tail -1`/bin; XCODE_NODE_PATH=`xcode-select --print-path`/usr/share/xcs/Node/bin; PATH=$NODEJS_PATH:$NVM_NODE_PATH:$N_NODE_PATH:$XCODE_NODE_PATH:$PATH && node cordova/lib/copy-www-build-step.js
如图:
Build Phases -> Target Dependencies -> CordovaLib
Build Phases -> Link Binary With Libraries -> libCordova.a
#import <Cordova/CDVViewController.h> #import <Cordova/CDVCommandDelegateImpl.h> #import <Cordova/CDVCommandQueue.h> @interface ViewController : CDVViewController @end
至此,Cordova嵌入已存的开发项目就已经完成了,运行程序就可看到工程中www文件目录下,index.html文件中的网页信息了。只须要将该文件内容,改成公司须要的网页内容便可。具体交互以及自定义插件,将在后面文章中介绍。
config.xml
文件中加入下面代码:<feature name="YourPluginName"> <param name="ios-package" value="Plugin" /> <param name="onload" value="true" /> </feature>
下面介绍一个简单的web端调用原生手机相机以及选择相册图片并返回web显示的自定义插件调用:
#import <Cordova/CDVPlugin.h> @interface Plugin : CDVPlugin { UIImagePickerController *_imagePickerController;//相机 } - (void)myMethod:(CDVInvokedUrlCommand *)command; @end
#import "Plugin.h" typedef void(^imgBlock)(NSString *data); @interface Plugin() <UIImagePickerControllerDelegate, UINavigationControllerDelegate> @property (copy, nonatomic) imgBlock myBlock; @end @implementation Plugin - (void)myMethod:(CDVInvokedUrlCommand *)command { [self.commandDelegate runInBackground:^{ NSString* myarg = [command.arguments objectAtIndex:0]; if (myarg !=nil) { [self switchMethodWithName:myarg andCommand:(CDVInvokedUrlCommand*)command]; }else{ return ; } }]; } // 根据方法选择判断调用具体内容 - (void)switchMethodWithName:(NSString *)name andCommand:(CDVInvokedUrlCommand*)command{ _imagePickerController = [[UIImagePickerController alloc] init]; _imagePickerController.delegate = self; _imagePickerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; _imagePickerController.allowsEditing = YES; __block CDVPluginResult* pluginResult = nil; NSString * standbyJSStr = [NSString stringWithFormat:@"%@",@"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAVCAYAAACt4nWrAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia219thzg25abkRE/BpDc3pqvphHvRFys2weqvp+krbWKIX7nhDbzLOItiM8358pTwdirqpPFnMF2xLc1WvLyOwTAibpbmvHHcvttU57y5+XqNZrLe3lE/Pq8eUj2fXKfOe3pfOjzhJYtB/yll5SDFcSDiH+hRkH25+L+sdxKEAMZahrlSX8ukqMOWy/jXW2m6M9LDBc31B9LFuv6gVKg/0Szi3KAr1kGq1GMjU/aLbnq6/lRxc4XfJ98hTargX++DbMJBSiYMIe9Ck1YAxFkKEAG3xbYaKmDDgYyFK0UGYpfoWYXG+fAPPI6tJnNwb7ClP7IyF+D+bjOtCpkhz6CFrIa/I6sFtNl8auFXGMTP34sNwI/JhkgEtmDz14ySfaRcTIBInmKPE32kxyyE2Tv+thKbEVePDfW/byMM1Kmm0XdObS7oGD/MypMXFPXrCwOtoYjyyn7BV29/MZfsVzpLDdRtuIZnbpXzvlf+ev8MvYr/Gqk4H/kV/G3csdazLuyTMPsbFhzd1UabQbjFvDRmcWJxR3zcfHkVw9GfpbJmeev9F08WW8uDkaslwX6avlWGU6NRKz0g/SHtCy9J30o/ca9zX3Kfc19zn3BXQKRO8ud477hLnAfc1/G9mrzGlrfexZ5GLdn6ZZrrEohI2wVHhZywjbhUWEy8icMCGNCUdiBlq3r+xafL549HQ5jH+an+1y+LlYBifuxAvRN/lVVVOlwlCkdVm9NOL5BE4wkQ2SMlDZU97hX86EilU/lUmkQUztTE6mx1EEPh7OmdqBtAvv8HdWpbrJS6tJj3n0CWdM6busNzRV3S9KTYhqvNiqWmuroiKgYhshMjmhTh9ptWhsF7970j/SbMrsPE1suR5z7DMC+P/Hs+y7ijrQAlhyAgccjbhjPygfeBTjzhNqy28EdkUh8C+DU9+z2v/oyeH791OncxHOs5y2AtTc7nb/f73TWPkD/qwBnjX8BoJ98VVBg/m8AAAEFSURBVDgRY/z969//GO9HDAd3f2agNmDKjX9KE4NBDmXasPwDTgcX14sxPP+vg4JBYsQCJmIVkqNu1HCsoUbTYGEJiBBgCE8SZLCw5WTg4CDeLkt7bgYrB24UFx878JXh+MGvcDGW6ctl4BxSGCCDSxpQk2VPwysUw4l3Kik2Q9XS1HAWkCV//vxn2LL2M8Od6z9Q3AfyOnq4oiggwGF5++YvQ4TzA4Yrl75jUSpGkeFMM3re4DAYi10kCjHt3kb9ohbmBqZHN3/B2FSnmdg4GaluKMxAJitn1FwGk6AGzZRXKcrAykId16Obw2RgwsmwYJMcg4omBwOlVniH8jFISbPBPQ0Ay3NHXHSKRhIAAAAASUVORK5CYII="]; if ([name isEqualToString:@"调用相机"]) { [self selectImageFromCameraWithBlock:^(NSString *data) { // 因当前转码格式为iOS原生转码,web端没法解析 ,因此百度了一波图片转码成功后复用,若转码格式正确 可直接上传字符串 // NSString *jsStr = [NSString stringWithFormat:@"data:image/png;base64,%@",data]; // 使用备用字符串上传 pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:standbyJSStr]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; }]; }else if ([name isEqualToString:@"查看相册"]){ [self selectImageFromAlbumWithBlock:^(NSString *data) { // 因当前转码格式为iOS原生转码,web端没法解析 ,因此百度了一波图片转码成功后复用,若转码格式正确 可直接上传字符串 // NSString *jsStr = [NSString stringWithFormat:@"data:image/png;base64,%@",data]; // 使用备用字符串上传 pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:standbyJSStr]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; }]; }else { pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"You Are Error"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } } #pragma mark 从摄像头获取图片或视频 - (void)selectImageFromCameraWithBlock:(imgBlock)block{ self.myBlock = block; _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; //相机类型(拍照、录像...)字符串须要作相应的类型转换 //视频上传质量 //UIImagePickerControllerQualityTypeHigh高清 //UIImagePickerControllerQualityTypeMedium中等质量 //UIImagePickerControllerQualityTypeLow低质量 //UIImagePickerControllerQualityType640x480 _imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; //设置摄像头模式(拍照,录制视频)为录像模式 _imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; [self.viewController presentViewController:_imagePickerController animated:YES completion:nil]; } #pragma mark 从相册获取图片或视频 - (void)selectImageFromAlbumWithBlock:(imgBlock)block{ self.myBlock = block; _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; [self.viewController presentViewController:_imagePickerController animated:YES completion:nil]; } #pragma mark UIImagePickerControllerDelegate //该代理方法仅适用于只选取图片时 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo { NSString *encodedImageStr = [self imageProcessing:image]; self.myBlock(encodedImageStr); } //适用获取全部媒体资源,只需判断资源类型 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{ NSString *encodedImageStr = [self imageProcessing:info[UIImagePickerControllerEditedImage]]; self.myBlock(encodedImageStr); [self.viewController dismissViewControllerAnimated:YES completion:nil]; } // 图像处理 若未下载base64者 可不用查看 - (NSString *)imageProcessing:(UIImage *)proImage{ // 判断传过来照片的大小进行裁剪 CGFloat width = proImage.size.width; CGFloat height = proImage.size.height; CGSize size; if (width>height) { size = CGSizeMake(800, 450); }else { size = CGSizeMake(450, 800); } // 建立一个bitmap的context // 并把它设置成为当前正在使用的context UIGraphicsBeginImageContext(size); // 绘制改变大小的图片 [proImage drawInRect:CGRectMake(0,0, size.width, size.height)]; // 从当前context中建立一个改变大小后的图片 UIImage * tailoringImage =UIGraphicsGetImageFromCurrentImageContext(); // 使当前的context出堆栈 UIGraphicsEndImageContext(); // 判断图片大小进行压缩 NSData *imageData = UIImageJPEGRepresentation(tailoringImage,1.0); NSLog(@"imagedata == %lud,size.width = %f==%f",(unsigned long)imageData.length,tailoringImage.size.width,tailoringImage.size.height); if (imageData.length>100*1024) { if (imageData.length>1024*1024) { //1M以及以上 imageData=UIImageJPEGRepresentation(tailoringImage, 0.1); }else if (imageData.length>512*1024) {//0.5M-1M imageData=UIImageJPEGRepresentation(tailoringImage, 0.3); }else if (imageData.length>200*1024) {//0.25M-0.5M imageData=UIImageJPEGRepresentation(tailoringImage, 0.7); } } NSLog(@"imagedata == %lud,size.width = %f==%f",(unsigned long)imageData.length,tailoringImage.size.width,tailoringImage.size.height); // 最后进行 base64 转码 // NSString * encodedImageStr = [GTMBase64 stringByEncodingData:imageData]; // 原生转码方法 NSString * encodedImageStr = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; return encodedImageStr; } @end
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="cordova_plugins.js"></script> <script type="text/javascript" src="jquery.min.js"></script> <script type="text/javascript"> document.addEventListener("deviceready", yourCallbackFunction, false); function cameraBTClick(){ Cordova.exec(successFunction, failFunction, "YanSYPlugin", "myMethod", ["调用相机"]); } function PhotoAlbumBTClick(){ Cordova.exec(failFunction, failFunction, "YanSYPlugin", "myMethod", ["查看相册"]); } function failFunction(error){ alert("error"); document.getElementById("returnValue").value = img; } function aaaa(){ document.getElementById("2").innerHTML = "<img src='data:image/png;base64," } function successFunction(img){ document.getElementById("returnValue").value = img; document.getElementById("2").innerHTML = "" } </script> </head> <body> <p>点击下面按钮调用相机拍照</p> <button onclick="cameraBTClick()">调用相机</button> </body> <body> <p>点击下面按钮选择相册照片</p> <button onclick="PhotoAlbumBTClick()">查看相册</button> <button onclick="aaaa()">测试</button> <h1>这是回调结果展现区</h1> <textarea id ="returnValue" type="value" rows="5" cols="40"> </textarea> </body> <body>/Users/YanSY/Desktop/代码运行示意11.gif <p> <img id="1" src=“”/> </p> <p id="2" > </p> </body> </html>
将以上代码,按步骤写入程序中,可测试调用原生相机,注意,须要在plist文件中添加隐私权限。运行效果示例以下只作到调用原生相机相册。
到这里基本结束了,须要Demo的点这里.
这样集成Cordova须要依赖cordova的一个工程,下篇文章介绍一种不须要依赖关系的方式,直接导入相关文件使用。