Ionic框架是Hybrid App,通过嵌入Cordova可以用Html5的形式开发App。Hybrid App代码的更新分为两种,一种是Native的更新,比如Cordova添加插件,一种是Html5和JavaScript的更新。第一种更新需要重新安装App,而第二种更新可以无须重新安装,直接热更新。
Ionic Pro为Ionic框架提供了及时更新App UI和业务逻辑的功能。
在Ionic Pro中创建应用
点击进入Ionic Pro的仪表盘,点击New App创建应用:
App关联Ionic Pro
情况一:还没创建对应的Ionic App,可以使用以下命令行创建相应的Ionic App。同时,Ionic会把创建的Ionic App与在Ionic Pro创建的应用关联:
ionic start --pro-id #你的App id#
cd cookies
情况二:已经存在Ionic App,可以使用以下命令把ionic App与Ionic Pro的应用关联
ionic link --pro-id #你的App id#
关联自己的git远程仓库
Ionic Pro不建议用户把代码存放在Ionic Pro中,因此还是需要有自己的git仓库,用于保存代码,等到某个阶段开发完毕,才把代码上传到App所属的Ionic Pro中。
使用下面的命令,为你的项目添加远程git仓库,并且上传代码到仓库:
git remote add origin [YOUR_REPOSITORY_URL]
git push -u origin master
把代码上传到Ionic Pro中
git push ionic master
添加Deploy插件
Ionic Pro具体提供了三种更新情况,我这里选择手动更新啊,会控制更加方便。在项目目录下运行以下命令添加插件:
cordova plugin add cordova-plugin-ionic --save \
--variable APP_ID="2c4aab3e" \
--variable CHANNEL_NAME="Master" \
--variable UPDATE_METHOD="none"
下面提供了工具类IonicDeploy:
declare var IonicCordova;
@Injectable()
export class IonicDeploy{
private isCordovaEnv: boolean = false;
// 是否已经初始化
private pluginWasInitialized: boolean = false;
private _channel: string = 'Master';
constructor(private platform: Platform,
private zone: NgZone) {
this.isCordovaEnv = platform.is('cordova');
}
// 初始化Deploy插件
init() {
this.onlyIfCordovaEnv();
return new Promise((resolve, reject) => {
IonicCordova.deploy.init({channel: this._channel}, () => {
this.pluginWasInitialized = true;
resolve(true);
}, err => reject(err));
});
}
// 检查是否有可用更新
check() {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.check(result => resolve((result === 'true') ? true : false), err => reject(err));
});
}
// 一个新版本可用下载
download(onProgress) {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.download(result => {
const percent = (result === 'true' || result === 100) ? 100 : result;
this.zone.run(() => onProgress(percent));
if (percent === 100) resolve();
}, err => {
reject(err);
});
});
}
// 解压最新版本
extract(onProgress) {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.extract(result => {
const percent = (result === 'done') ? 100 : result;
this.zone.run(() => onProgress(percent));
if (percent === 100) resolve();
}, err => {
reject(err);
});
});
}
// 加载最新版本
load() {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.redirect(() => resolve(true), err => reject(err));
});
}
// 获取该设备的当前版本信息
info() {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.info(result => resolve(result), err => reject(err));
});
}
// 获取该设备中已经下载的版本
getVersions() {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.getVersions(result => resolve(result), err => reject(err));
});
}
// 根据UUID删除该设备已经下载的版本
deleteVersion(uuid) {
this.onlyIfPluginInitialized();
return new Promise((resolve, reject) => {
IonicCordova.deploy.deleteVersion(uuid, () => resolve(true), err => reject(err));
});
}
// 判断是否为Cordova环境
private onlyIfCordovaEnv() {
if (!this.isCordovaEnv) {
console.error('IonicDeploy不能在非真实机器上运行!');
return;
}
}
// 检查插件是否已经初始化
private onlyIfPluginInitialized() {
if (!this.pluginWasInitialized) {
console.error('IonicDeploy未被初始化, 你需要先执行init方法!');
return;
}
}
}
调用上面的工具方法:
update(){
if (this.platform.is('cordova')) {
if (this.runningDeploy) return;
let toast = this.toastCtrl.create({
message: '下载中 ... 0%',
position: 'top',
showCloseButton: false,
closeButtonText: '关闭'
});
this.ionicDeploy.init()
.then(() => this.ionicDeploy.check())
.then(snapshotAvailable => {
toast.present();
if (snapshotAvailable) {
this.runningDeploy = true;
return this.ionicDeploy.download(percent => toast.setMessage('下载中 ... ' + percent + '%'));
}else{
// 检查到没有更新,则中止下面的链式then
return Promise.reject({
snapshotAvailable: false
});
}
})
.then(() => this.ionicDeploy.extract(percent => toast.setMessage('解压中 ... ' + percent + '%')))
.then(() => this.ionicDeploy.load())
.then(() => toast.dismiss())
.then(() => this.runningDeploy = false)
.catch(ex => {
if (!ex.snapshotAvailable){
toast.setMessage('该版本已是最新版,不需要更新!');
toast.setDuration(3000);
}else{
this.runningDeploy = false;
toast.setMessage('对不起,由于网络问题更新失败, 请在次手动更新!');
toast.setDuration(3000);
}
})
}else{
console.error('版本热更新不能在非真实机器上运行!')
}
}
上面提供了控制更新的方法。代码写完后,提交到Ionic Pro,触发update方法,App就会检测到更新,自动更新代码。
关于版本的控制
如何查看App壳的版本?我们可以打开项目根目录下的config.xml文件,version记录了当前App壳的版本号。
下图里,看到更新的记录,点击版本号进去,可以看到版本好设置:
- Minium:允许更新的最小版本
- Maximum:允许更新的最大版本
- Equivalent:当App版本号等于此值时,不需要更新这个build