一:關於Cordoval理論知識
1:PhoneGap是手機平台上流行的一款中間件。它構建在各種手機平台所提供的WebView(瀏覽器內核)組件的基礎之上,使用javascript語言對應用開發者提供統一的接口(如調用相機、調用其他本地組件),從而屏蔽了各手機平台上OS的異構。在無線小組的調研任務中,我的任務主要是負責iOS平台上的調研,本文簡單描述了iOS平台上PhoneGap與平台本地的互操作性的實現。
2:PhoneGap因為被捐贈給了Apache而改名為Cordova,所以PhoneGap里的類名都以CDV作為前綴。在iOS平台上,最重要的一個核心類是CDVViewController。該類直接繼承自UIViewController,因而具備了所有UIViewController所具備的特性。同時,該類還實現了兩個Protocol(即接口):UIWebViewDelegate和CDVCommandDelegate。因此它也負責UIWebView的一些callback,以及CDVInvokedUrlCommand的執行。
3:CDVViewController類的主要對象成員是CDVCordovaView *webView,在源代碼中可以看出,這個webView對象是CDVViewController的self.view上的唯一被add進來的子對象,即負責了整個CDVViewController類的顯示。而CDVCordovaView類則沒什么特別的,它直接繼承自UIWebView。
4:當CDVViewController在構建時,它有兩個很重要的屬性:NSString*wwwFolderName和NSString *startPage。這兩個屬性值使得CDVViewController在load之后直接加載wwwFolderName下的startPage作為初始顯示的頁面。
以上是對CDVViewController的一個簡單介紹。容易明白的是,在iOS應用中使用了CDVViewController之后,界面實際上就完全交給了CDVCordovaView*webView,即一個UIWebView。
二:使用Cordoval常碰到的問題
config.xml 是一個用來配置應用的全局屬性的文件, 在此文件中配置的屬性應該是能適應所有平台的. 在編譯的時候配置文件將會被編譯到對應的平台中.
1:如何在Cordoval加載遠程的URL網址
在Config.xml配置文件時增加下面兩個,便可以打開URL的HTML頁面
<allow-navigation href="http://*/*" /> <allow-navigation href="https://*/*" />
2:在Cordoval中加載同一個域的URL是在APP打開,跳轉到其它卻是用safari瀏覽器打開
同樣是在Config.xml配置中把下面兩個刪除,這樣它便會一直在APP里面進行跳轉
<!-- <allow-intent href="http://*/*" />--> <!-- <allow-intent href="https://*/*" />-->
2.1:禁用 WebViewBounce
UIWebView是iOS SDK中一個最常用的控件, 在Cordova中, 默認也是使用UIWebView作為默認視圖顯示我們的HTML應用的.
在使用Cordova的項目中, 默認WebViewBounce這個選項是打開的, 所以使用手指向下或者向上滑動屏幕時, 經常會看到頁面底部和屏幕底部會出現一大片空白, 然后松開手指后, 再彈回去的特效.
<preference name="WebViewBounce" value="false" /> <preference name="DisallowOverscroll" value="true" />
2.2:config.xml access配置
只允許google.com Access to google.com:
<access origin="http://google.com" />
只允許google.com的https協議 Access to the secure google.com (https://):
<access origin="https://google.com" />
二級域名(maps) Access to the subdomain maps.google.com:
<access origin="http://maps.google.com" />
所有二級域名 Access to all the subdomains on google.com, for example mail.google.com and docs.google.com:
<access origin="http://*.google.com" />
所有域名 Access to all domains, for example, google.com and developer.mozilla.org:
<access origin="*" />
2.3:config.xml Navigation Whitelist
說明:webview可以跳轉至的URL
<!-- 允許所有到example.com的鏈接 --> <!-- Allow links to example.com --> <allow-navigation href="http://example.com/*" /> <!-- 通配符 --> <!-- Wildcards are allowed for the protocol, as a prefix to the host, or as a suffix to the path --> <allow-navigation href="*://*.example.com/*" /> <!-- 通配符(全) *不推薦* --> <!-- A wildcard can be used to whitelist the entire network, over HTTP and HTTPS. *NOT RECOMMENDED* --> <allow-navigation href="*" /> <!-- 上面的寫法與下面3句等價 --> <!-- The above is equivalent to these three declarations --> <allow-navigation href="http://*/*" /> <allow-navigation href="https://*/*" /> <allow-navigation href="data:*" />
2.4:config.xml Intent Whitelist
說明:系統可以打開的鏈接
<!-- Allow links to web pages to open in a browser --> <allow-intent href="http://*/*" /> <allow-intent href="https://*/*" /> <!-- Allow links to example.com to open in a browser --> <allow-intent href="http://example.com/*" /> <!-- Wildcards are allowed for the protocol, as a prefix to the host, or as a suffix to the path --> <allow-intent href="*://*.example.com/*" /> <!-- Allow SMS links to open messaging app --> <allow-intent href="sms:*" /> <!-- Allow tel: links to open the dialer --> <allow-intent href="tel:*" /> <!-- Allow geo: links to open maps --> <allow-intent href="geo:*" /> <!-- Allow all unrecognized URLs to open installed apps *NOT RECOMMENDED* --> <allow-intent href="*" />
2.5:config.xml Network Request Whitelist
說明:網絡請求(如XHR等)白名單
<!-- Allow images, xhrs, etc. to google.com --> <access origin="http://google.com" /> <access origin="https://google.com" /> <!-- Access to the subdomain maps.google.com --> <access origin="http://maps.google.com" /> <!-- Access to all the subdomains on google.com --> <access origin="http://*.google.com" /> <!-- Enable requests to content: URLs --> <access origin="content:///*" /> <!-- Don't block any requests --> <access origin="*" />
2.6:index.html Content Security Policy
說明:頁面上的資源白名單
主要分這幾類:default-src,style-src,script-src,img-src,font-src,media-src 等
參數值可以是:*,'self','unsafe-inline',data: 等
我使用的是非常寬松的策略:
允許所有域名的數據,允許不安全的內聯,允許data:(主要用於BASE64形式的圖片,字體等)
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline';img-src * 'self' data:;font-src 'self' data:">
3:如何加載不同的啟動頁URL地址
在配置Config.xml文件中有個content的節點,里面默認是有一個打開本地的地址index.html(比如:<content src="index.html" />); 這個就是跳轉到本地包里面的html頁面,也可以修改成(比如:<content src="https://www.baidu.com/" />);
上面這種只是修改默認的地址,可能不符合對於項目實際用法,項目中要加載Cordova都會有一個viewController的控制器繼承於CDVViewController,它時就有一個屬性startPage用於設置跳到webView加載的html頁面;其中使用CDVViewController通常需要設置wwwFolderName的目錄名稱,和startPage首頁的名稱即可。默認wwwFolderName為www,startPage默認為index.html;這個也是模板直接生成時文件的名稱;
self.viewController.startPage=@"http://www.cnblogs.com";
4:如何加載HTML頁面存放在盒沙中
self.viewController = [[MainViewController alloc] init]; NSString *curFilePath=[NSString stringWithFormat:@"file://%@/www",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]]; NSLog(@"路徑為:%@",curFilePath); if ([[NSFileManager defaultManager] fileExistsAtPath:curFilePath]) { self.viewController.wwwFolderName = curFilePath; } self.viewController.startPage=@"index.html";
同樣是在wwwFolderName上做文章,因為它是前綴文件夾的路徑,這邊要注意是關於路徑要運用file://方式進行讀取;
因為可以讀取沙盒里面的HTML頁面,這樣我們就可以更加靈活運用,比如HTML通過服務端去下載到沙盒解壓,這樣就可以做到動態修改;
5:加載頁面跟結束加載頁面的監聽,有兩個通知可以監聽,用來處理等待效果展現
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(onNotification:) name:CDVPluginResetNotification // 開始加載 object:nil]; [center addObserver:self selector:@selector(onNotificationed:) name:CDVPageDidLoadNotification // 加載完成 object:nil]; } - (void)onNotification:(NSNotification *)text{ NSLog(@"-----開始等待------"); } - (void)onNotificationed:(NSNotification *)text{ NSLog(@"-----結束等待------"); }
6:刷新UIWebView,UIWebView直接更改url並reload是沒有用的。必須聲明一個NSURLRequest,並重新loadRequest。刷新時的url必須是符合Cordova規則的url。在Cordova源碼中有一個appUrl的方法,通過這個方法轉出的url才能被CDVViewController正常加載;
localWebVC.wwwFolderName = @"www"; localWebVC.startPage = @"local.html"; NSURL *url = [self.localWebVC performSelector:@selector(appUrl)]; if (url) { NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; [self.localWebVC.webView loadRequest:request]; }
7:使用pod管理Cordoval及其插件(IOS8以上才可以使用到最新版本)
pod 'Cordova'
如果需要引入一些相關的插件,可以加入如下配置,下面的這些插件可以通過pod搜索到:
pod 'CordovaPlugin-console' pod 'cordova-plugin-camera' pod 'cordova-plugin-contacts' pod 'cordova-plugin-device' pod 'cordova-plugin-device-orientation' pod 'cordova-plugin-device-motion' pod 'cordova-plugin-globalization' pod 'cordova-plugin-geolocation' pod 'cordova-plugin-file' pod 'cordova-plugin-media-capture' pod 'cordova-plugin-network-information' pod 'cordova-plugin-splashscreen' pod 'cordova-plugin-inappbrowser' pod 'cordova-plugin-file-transfer' pod 'cordova-plugin-statusbar' pod 'cordova-plugin-vibration'
注意:如果沒有用pod來管理Cordova,默認工程都會有一個CordovaLib.xcodeproj來把Cordova的類引入,所以建議Cordova用pod引入,就可以調用,而關於html、JS等靜態模板還是在工程中;可以查看下面兩個網址
iOS中Cordova開發初探 地址:http://blog.devzeng.com/blog/hello-cordova-ios.html
Cordova使用Pod實例 地址:https://github.com/phonegap/phonegap-webview-ios 【POD引入的模塊都存在】
三:插件內容
對於Cordova在插件上面還是比較多,也可以自定義插件的開發,對於插件下面已經有列出一些,其它插件可以上Cordova或者gitHub進行查找;
支付寶支付插件: iOS/Android 地址:https://github.com/fami2u/cordova-plugin-alipay.git 微信支付插件: iOS/Android 地址:https://github.com/fami2u/cordova-plugin-weipay.git ping++支付插件: iOS 地址:https://github.com/fami2u/cordova-ping-fami.git 掃描二維碼和條形碼插件: iOS/Android 地址:https://github.com/fami2u/cordova-barcodescanner-fami.git 拍照插件: iOS/Android 地址:https://github.com/fami2u/cordova-plugin-camera.git 極光推送插件: iOS/Android 地址:https://github.com/fami2u/jpush-phonegap-plugin.git iOS 地址:https://github.com/fami2u/cordova-Jpush-fami.git 第三方登錄插件: iOS 地址:https://github.com/fami2u/cordova-UMLogin-fami.git JS 地址:https://github.com/fami2u/cordova-plugin-wechat.git 第三方分享插件: iOS 地址:https://github.com/fami2u/cordova-UMShare-fami.git 跳轉地圖插件: iOS 地址:https://github.com/fami2u/cordova-plugin-map.git 視頻播放插件: iOS 地址:https://github.com/fami2u/cordova-player-fami.git
四:有可能出現的問題
1:在使用cordova6.0的過程中,編譯好的APP運行在IOS7+系統上默認是與狀態欄重疊的,而運行在IOS6及老版本中時是於狀態欄分離的。
解決辦法:把文件MainViewController.m中的方法viewWillAppear進行相關修改如下。 作用是更改view的邊界,使其下移20px,剛好是狀態欄的高度。
- (void)viewWillAppear:(BOOL)animated { if([[[UIDevice currentDevice]systemVersion ] floatValue]>=7) { CGRect viewBounds=[self.webView bounds]; viewBounds.origin.y=20; viewBounds.size.height=viewBounds.size.height-20; self.webView.frame=viewBounds; } [super viewWillAppear:animated]; }
2:在html頁面內調用系統相機以后再返回,整個頁面底部會有白色的空白控件,用調試工具查看后空白區域的高度是20px.該如何解決?
解決辦法:由於整個cordova項目相當於一個頁面的應用,不同的模塊聚集在一起,所以當當前屏幕消失后(比如進入系統相機拍照頁面)再出現的時候,還是會執行上面的代碼,所以界面高度再次減少20px.
-(void)viewWillDisappear:(BOOL)animated { if([[[UIDevice currentDevice]systemVersion ] floatValue]>=7) { CGRect viewBounds=[self.webView bounds]; viewBounds.origin.y=20; viewBounds.size.height=viewBounds.size.height+20; self.webView.frame=viewBounds; } [super viewWillDisappear:animated]; }
五:不錯的使用總結:
六:JS跟OC交互實例
1:因為Cordoval要跟JS交互都是要利用CDVPlugin進行
#import <Foundation/Foundation.h> #import <Cordova/CDVPlugin.h> @interface CDVHelloWorld : CDVPlugin -(void)sayHello:(CDVInvokedUrlCommand *)command; @end
所以我們創建一個插件類,繼承於CDVPlugin類,其中CDVInvokedUrlCommand就是用於交互的類;
#import "CDVHelloWorld.h" @implementation CDVHelloWorld -(void)sayHello:(CDVInvokedUrlCommand *)command { //接收JS傳過來的值 NSDictionary *options=[command argumentAtIndex:0 withDefault:nil]; //對應鍵名 NSString *curValue=options[@"quality"]; UIAlertView *myAlertView=[[UIAlertView alloc]initWithTitle:@"我是小實例" message:[NSString stringWithFormat:@"當前的內容從JS傳過來的值為:%@",curValue] delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil]; [myAlertView show]; //數據回調 if ([curValue isEqualToString:@"200"]) { curValue=@"201"; } CDVPluginResult *pluginResult=[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"OC回調過來的值"]; [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } @end
上面的實例有接收JS傳過來的值,也有再回調給JS的值,回調時要利用self.commandDelegate;其中CDVPluginResult里面包括很多狀態,上面只是把正確的狀態賦值傳回去,而messageAsString只是會字符串,還有其它類型的,比較字典、數組等;
2:config.xml修改配置,注冊剛才我們注冊的這個插件,給它定義一個HelloWorld的名字,value則是我們剛才創建的類名
<feature name="HelloWorld"> <param name="ios-package" value="CDVHelloWorld" /> </feature>
3:Html跟JS的代碼,sayHello則是我們類中的一個方法名,HelloWorld則是我們在配置中的那個名字,可以對它進行傳參;
<!DOCTYPE html> <html> <head> <title>Capture Photo</title> <script type="text/javascript" charset="utf-8" src="cordova.js"></script> <script type="text/javascript" charset="utf-8"> //簡單跟OC交互,沒有回調 //function test() //{ // options={quality:"200"}; // cordova.exec(null,null,'HelloWorld','sayHello',[options]); //} function test() { options={quality:"200"}; cordova.exec( function(result){ var s=result; alert(s); }, function(error) { alert("error",error); } ,'HelloWorld','sayHello',[options]); } </script> </head> <body> <button onclick="test();">交互OC</button> <br> </body> </html>
可以查看文章對於插件的編寫有進一步的說明,http://www.jianshu.com/p/e982b9a85ae8
七:分享Cordova不錯的文章:
使用Cordova進行iOS開發 (環境配置及基本用法) :http://www.jianshu.com/p/d24219c008b6
使用Cordova進行iOS開發 (第三方插件的使用:Camera插件):http://www.jianshu.com/p/1e3d0c915dbc
使用Cordova進行iOS開發 (已存的項目中添加Cordova及自定義插件):http://www.jianshu.com/p/e982b9a85ae8
Cordova插件開發入門(IOS版OC跟JS交互):http://my.oschina.net/crazymus/blog/516388
淺析 Cordova for iOS(OC跟JS交互的說明):http://www.cocoachina.com/industry/20130520/6238.html
cordova CDVViewController解析 :http://blog.csdn.net/u011417590/article/details/50895734
附整理的Cordova小實例:https://github.com/wujunyang/jiaCordovaDemo
最近有個妹子弄的一個關於擴大眼界跟內含的訂閱號,每天都會更新一些深度內容,在這里如果你感興趣也可以關注一下(嘿對美女跟知識感興趣),當然可以關注后輸入:github 會有我的微信號,如果有問題你也可以在那找到我;當然不感興趣無視此信息;