很多項目可能是在中途才從純原生轉向Hybrid蕴纳,那就涉及到將Ionic导帝、React Native等開發(fā)的功能模塊集成到已有的原生安卓項目中堡称,那么非原生的部分當然就需要熱更新了,否則每次都打包apk就失去這么做的意義了墙贱。
本人也是在網上查看了一些文章热芹,看了一些相關書本,把項目集成好了決定整理一下寫下本文惨撇,供大家參考伊脓,有不對的地方歡迎指出。
環(huán)境:
Android Studio 3.2 + JDK 1.8 + node.js 10.13.0 + ionic 4.3.1 + cordova 8.1.2 + code-push 2.1.9
npm命令搭建Ionic的環(huán)境咱就跳過吧(0_0)
參考:
Ionic創(chuàng)建項目以及集成code-push官方文檔: https://ionicframework.com/docs/native/code-push/
Ionic集成到原生安卓項目:https://blog.csdn.net/qq_42618969/article/details/81173034
創(chuàng)建項目:
首先打開命令行魁衙,進入指定路徑(項目路徑根據個人情況自行修改)报腔,一波連續(xù)操作:
ionic start codepush-ionic-test tabs
創(chuàng)建tabs基礎ionic項目(這里我并沒有選擇使用Ionic4,Ionic的資料有點少剖淀,所以不想用beta版本給自己找坑)
cd codepush-ionic-test
進入項目文件夾
ionic cordova plugin add cordova-plugin-code-push
添加code-push插件
npm install --save @ionic-native/code-push
node_modules添加code-push庫
ionic cordova platform add android
Ionic添加安卓平臺支持(不添加的話項目只是web,蘋果平臺將android改為ios即可)
npm install
安裝code-push-cli(這個一定加上-g表明全局安裝纵隔,以后就可以省略這步)
npm install -g code-push-cli
登錄code-push(這一步會自動打開電腦瀏覽器翻诉,注冊賬號或者使用github賬號登錄都行炮姨,登錄后會給一個token)
code-push login
在code-push中創(chuàng)建項目(蘋果端替換android為ios)
code-push app add codepush-ionic-test-android android cordova
如果已經創(chuàng)建了項目忘記了項目的key可以通過這個命令查看
code-push deployment ls codepush-ionic-test-android -k
在項目根目錄打開config.xml,將code-push的key添加進去
<platform name="android">
<preference name="CodePushDeploymentKey" value="*******" />
</platform>
<platform name="ios">
<preference name="CodePushDeploymentKey" value="*******" />
</platform>
編輯src/app/app.module.ts代碼如下(這個有點像安卓中的build.gradle碰煌,這里主要是設置CodePush庫引用):
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { CodePush } from '@ionic-native/code-push';
@NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage
],
providers: [
StatusBar,
SplashScreen,
CodePush,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
編輯src/app.component.ts添加熱更新的檢查更新方法(這個有點類似application初始化):
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { HomePage } from '../pages/home/home';
import { CodePush, InstallMode, SyncStatus } from '@ionic-native/code-push';
import { AlertController } from 'ionic-angular/components/alert/alert-controller';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage:any = HomePage;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen,
private codePush: CodePush, private alertCtrl: AlertController) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
this.checkCodePush(); //Use the plugin always after platform.ready()
});
}
checkCodePush() {
this.codePush.sync({
updateDialog: {
appendReleaseDescription: true,
descriptionPrefix: "\n\nChange log:\n"
},
installMode: InstallMode.IMMEDIATE
}).subscribe(
(data) => {
console.log('CODE PUSH SUCCESSFUL: ' + data);
},
(err) => {
console.log('CODE PUSH ERROR: ' + err);
}
);
}
}
接下來在電腦瀏覽器運行一下舒岸,繼續(xù)命令行
ionic serve
到這里就已經將Ionic集成code-push了,最后編譯安卓項目
ionic cordova build android
集成到原生安卓項目
Ionic項目中找到安卓項目芦圾,就在platforms文件夾里面(ios項目路徑也在這)吁津,這已經是一個能直接用Android Studio打開的項目了。
1堕扶、將其中的CordovaLib整個文件夾拷貝到要集成的原生安卓項目中碍脏,在gradle配置一下作為module。
2稍算、將項目中res/xml/config.xml文件拷貝到原生項目中典尾,將Ionic項目中的“org文件夾、io文件夾”拷貝到原生項目的main/java下糊探。
3钾埂、接下來是將Ionic中寫的功能相關代碼拷貝到原生項目中,也就是assets中的www文件夾科平,里面才是在Ionic中的代碼褥紫,而熱更新便是更新這里面的內容。
其實如果是集成Ionic到原生項目的話瞪慧,到這里已經完成了髓考,但是code-push還沒放進去。
4弃酌、在安卓原生項目中添加依賴(這個庫在Ionic安卓項目的cordova-plugin-code-push/starter-build-extras.gradle中添加了引用)
implementation 'com.nimbusds:nimbus-jose-jwt:5.1'
5氨菇、拷貝Ionic安卓項目中的src/main/java/com到原生安卓項目中,最后原生項目文件結構如圖所示(馬賽克是原生項目本來的代碼):
到這里整個項目集成Ionic + code-push就基本完成了妓湘,隨便找個地方從原生項目跳轉進Ionic的功能模塊里面(跳轉activity就好查蓉,跳到io.ionic.starter.MainActivity,記得到AndroidManifest.xml中添加這個Activity榜贴,這里為了省事我把Ionic的路徑直接一起傳過去)
Bundle bundle = new Bundle();
bundle.putString("url", "file:///android_asset/www/index.html");
IntentUtils.startActivity(mActivity, MainActivity.class, bundle);
再稍微改一下io.ionic.starter.MainActivity
public class MainActivity extends CordovaActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// enable Cordova apps to be started in the background
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
// Set by <content src="index.html" /> in config.xml
loadUrl(getIntent().getStringExtra("url"));
}
}
這時已經可以運行原生安卓項目了豌研。當然,還有熱更新沒測試唬党,再回到Ionic項目中鹃共,打開源碼src文件夾隨便修改點東西,然后命令行編譯一下
ionic cordova prepare android
這時候再上傳推送包到微軟的code-push中初嘹,命令中的0.0.1是版本號及汉,用原生安卓項目的versionName的值,--description后面跟的是熱更新包的說明屯烦,-d后面跟的是推送分支坷随,code-push創(chuàng)建項目后便會生成正式線和測試線兩個分支房铭,
code-push release codepush-ionic-test-android ./platforms/android/app/src/main/assets/www/ 0.0.1 --description "Your awesome change description" -d "Staging"
題外:
1、熱更新檢查可以不彈框提示采取靜默安裝温眉,具體的就自行去修改Ionic那部分代碼了缸匪,畢竟ios審核禁止熱更新,還是不能光明正大的类溢。配置在config.xml里面熱更新使用的key也可以動態(tài)修改凌蔬,在代碼里控制測試線、正式線以及ios和android闯冷,自己去做判斷就好砂心,簡單上幾行代碼:
//根據平臺修改key
if (this.platform.is('android')) {
key = '';
} else if (this.platform.is('ios')) {
key = '';
}
//定義檢查更新參數
let options = {
installMode:InstallMode.ON_NEXT_RESUME,
deploymentKey:key
}
//檢查更新方法
checkCodePush() {
this.codePush.sync(options,(data) => {
}).subscribe(
(data) => {
console.log('CODE PUSH SUCCESSFUL: ' + data);
},
(err) => {
console.log('CODE PUSH ERROR: ' + err);
}
);
}
2、檢查更新有幾個模式蛇耀,這里用的是啟動Ionic的時候檢查更新辩诞,其它的自己加代碼吧,類似這樣:
//從后臺回到應用時檢查更新
this.platform.resume.subscribe(() => {
this.checkCodePush();
});
3纺涤、另外說一下本人在集成過程中踩的一個坑译暂,因為用fiddler抓包,手機設置了代理撩炊,將集成好的安卓項目打包release包運行時外永,發(fā)現code-push不檢測更新,在代碼里找了好幾圈拧咳,看Android Studio中的Logcat發(fā)現日志出現了檢測更新的請求册着,說網絡連接有問題壤短,才明白code-push對網絡有做檢查台汇,release包運行一旦有網絡代理就不會發(fā)起請求即纲,這是https加密傳輸的SSL證書問題,具體的就不深究了谭网。
4、這里使用的是微軟code-push的服務赃春,也可以自行搭建一個code-push服務端愉择。
5、當然了织中,可以把www文件夾以及cdvasset.manifest文件放到自定義路徑:
一是使用自己的方式更新文件锥涕,只需要修改跳轉io.ionic.starter.MainActivity時傳過去的頁面路徑即可修改ionic頁面訪問。
//正常情況下讀取文件我們會這樣寫路徑
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "www/index.html"
//在這里需要加個前綴狭吼,像原本assets路徑類似
String path = "file:" + Environment.getExternalStorageDirectory().getAbsolutePath() + "www/index.html"
還有就是把codepush熱更新的路徑也改掉层坠,需要修改三個地方:
// com.microsoft.cordova.CodePush中的WWW_ASSET_PATH_PREFIX常量
private static final String WWW_ASSET_PATH_PREFIX = "file:" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/www/";
// org.apache.cordova.ConfigXmlParser中的setStartUrl方法,這里是設置開始頁面
launchUrl = "file:" + Environment.getExternalStorageDirectory().getAbsolutePath()+"/www/index.html";
// org.apache.cordova.file.AssetFilesystem中的lazyInitCaches方法刁笙,注意這里無須添加“file:”破花,將原本打開assets路徑文件改為普通的打開文件并轉換成InputStream對象(FileInputStream是InputStream的子類)
ois = new ObjectInputStream(new FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath()+"/cdvasset.manifest"));
最后說一下谦趣,code-push一旦進行過熱更新后,文件會保存到內部存儲中座每,真正自定義還需要修改CodePush以及Cordova其它代碼前鹅。
發(fā)包對應APP版本范圍表達式
1.2.3——僅僅只有1.2.3的版本
*——所有版本
1.2.x——主要版本1,次要版本2的任何修補程序版本
1.2.3 - 1.2.7——1.2.3版本到1.2.7版本
>=1.2.3 <1.2.7——大于等于1.2.3版本小于1.2.7的版本
~1.2.3——大于等于1.2.3版本小于1.3.0的版本
^1.2.3——大于等于1.2.3版本小于2.0.0的版本