項目組準備開發一個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 = "![]("+img+")" } </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的一個工程,下篇文章介紹一種不須要依賴關係的方式,直接導入相關文件使用。