没有angular基础,看一下这篇文章 http://blog.poetries.top/2019/01/09/angular7-intro-summary
一、介绍
Ionic 是一款基于 Angular、Cordova 的强大的 HTML5 移动应用开发框架 , 可以快速创建一 个跨平台的移动应用。可以快速开发移动 App、移动端 WEB 页面、微信公众平台应用,混 合 app web 页面。
1.1 ionic 特点
ionic 基于Angular语法,简单易学。
ionic 是一个轻量级框架。
ionic 完美的融合下一代移动框架,支持 Angularjs 的特性, MVC ,代码易维护。
ionic 提供了漂亮的设计,通过 SASS 构建应用程序,它提供了很多 UI 组件来帮助开发者开发强大的应用。
ionic 专注原生,让你看不出混合应用和原生的区别
ionic 提供了强大的命令行工具。
ionic 性能优越,运行速度快。
1.2 Ionic 和 Cordova(phonegap)、Angular 关系
ionic = Cordova + Angular + ionic CSS
Ionic 是完全基于谷歌的 Angular 框架,在 Angular 基础上面做了一些封装,让我们可以更快 速和容易的开发移动的项目。Ionic 调用原生的功能是基于 Cordova,Cordova 提供了使用 JavaScript 调用 Native 功能,ionic 自己也封装了一套漂亮的 CSS UI 库。
二、环境搭建 2.1 Ionic初始化构建
https://ionicframework.com/getting-started#cli
ionic info (查看当前ionic的全部版本信息)
ionic start myApp tabs cd myApp ionic serve
2.2 Genymotion 安卓模拟器
使用方法 https://www.jianshu.com/p/aabc4fd01311
2.3 在IOS环境下体验
需要配备mac,安装xcode
sudo ionic cordova platform add ioschmod -R 777 项目文件夹名
真机调试与发布需要Apple开发者账号
打开xcode选择platform下中ios文件夹,点击运行项目
2.4 在安卓下体验 1. 添加android
ionic cordova platform add android chmod -R 777 项目文件夹名
2. 下载android studio 打开/platform/andriod文件
3. 然后连接android studio结合geny生成apk调试
2.5 在浏览器/微信下体验 1. 添加browser文件夹
ionic cordova platform add browser
2. 打包
ionic cordova build browser
3. 运行
4. 部署
把www目录部署到服务器上即可
在微信下体验 注意微信title问题
2.6 ionic的常用命令 1. 基本命令
ionic g page myPage 创建页面
ionic g provider MyData 创建provider
ionic serve 在浏览器中看
ionic platform add/remove android/ios 添加删除平台
ionic build android/ios 快捷打包(IOS最好通过xcode打包发布)
2. 辅助命令
ionic info 查看关于ionic的系统消息
ionic emulate android/ios 模拟器中打开
ionic cordova plugin list 查看插件安装列表
3. 正式发布需要的命令
ionic cordova platforms add android 添加安卓平台
ionic cordova build android --release 打包成apk
三、Ionic3.x+ 目录结构分析及创建组件 3.1 Ionic3.x 目录结构分析 1. 整体目录结构
hooks:编译 cordova 时自定义的脚本命令,方便整合到我们的编译系统和版本控制系统中
node_modules :node 各类依赖包
resources :android/ios 资源(更换图标和启动动画)
src:开发工作目录,页面、样式、脚本和图片都放在这个目录下
www:静态文件
platforms:生成 android 或者 ios 安装包路径(platforms\android\build\outputs\apk:apk 所在位置)执行 cordova platform add android 后会生成
plugins:插件文件夹,里面放置各种 cordova 安装的插件
config.xml: 打包成 app 的配置文件
package.json: 配置项目的元数据和管理项目所需要的依赖
tsconfig.json: TypeScript 项目的根目录,指定用来编译这个项目的根文件和编译选项
tslint.json:格式化和校验 typescript
2. src目录
app:应用根目录
assets:资源目录(静态文件(图片,js 框架)
pages:页面文件,放置编写的页面文件,包括:html,scss,ts
theme:主题文件,里面有一个 scss 文件,设置主题信息。
3. Ionic3.x src 下面文件分析
4. app.module.ts 分析
import { NgModule , ErrorHandler } from '@angular/core' ;import { BrowserModule } from '@angular/platform-browser' ;import { HttpClientModule } from '@angular/common/http' ;import { IonicApp , IonicModule , IonicErrorHandler } from 'ionic-angular' ;import { IonicStorageModule } from '@ionic/storage' ;import { MyApp } from './app.component' ;import { HomePage } from '../pages/home/home' ;import { DiscoveryPage } from '../pages/discovery/discovery' ;import { ChatPage } from '../pages/chat/chat' ;import { NotificationPage } from '../pages/notification/notification' ;import { MorePage } from '../pages/more/more' ;import { LoginPage } from '../pages/login/login' ;import { TabsPage } from '../pages/tabs/tabs' ;import { StatusBar } from '@ionic-native/status-bar' ;import { SplashScreen } from '@ionic-native/splash-screen' ;import { ApiProvider } from '../providers/api/api' ;@NgModule ({ declarations : [ MyApp , HomePage , DiscoveryPage , ChatPage , NotificationPage , MorePage , LoginPage , TabsPage ], imports : [ BrowserModule , HttpClientModule , IonicModule .forRoot (MyApp ), IonicStorageModule .forRoot () ], bootstrap : [IonicApp ], entryComponents : [ MyApp , HomePage , DiscoveryPage , ChatPage , NotificationPage , MorePage , LoginPage , TabsPage ], providers : [ StatusBar , SplashScreen , {provide : ErrorHandler , useClass : IonicErrorHandler }, ApiProvider ] }) export class AppModule {}
3.2 创建组件
cd 到我们的项目目录
通过 ionic g component 组件名称创建组件
输入ionic g后,可以创建的组件如下
创建完成组件以后会在 src 目录下面多一个 components 的目录,这个目录里面有我们用命令创建的所有的组件
如果我们要使用这些组件必须在 app.module.ts 里面注册我们的模块,注册完成后就可以在 pages 里面的其页面里面使用这些组件
3.3 创建页面以及页面跳转 1. 创建页面
2. 跳转
<button ion-button (click )="pushButton" > 执行button跳转</button >
四、Ionic页面生命周期 onPageLoaded ( ) { console .log ('page 1: page loaded.' ); } onPageWillEnter ( ) { console .log ('page 1: page will enter.' ); } onPageDidEnter ( ) { console .log ('page 1: page did enter.' ); } onPageWillLeave ( ) { console .log ('page 1: page will leave.' ); } onPageDidLeave ( ) { console .log ('page 1: page did leave.' ); } onPageWillUnload ( ) { } onPageDidUnload ( ) { }
五、API的使用 5.1 图片上传
文档 https://ionicframework.com/docs/native
npm i --save @ionic-native/camera @ionic-native/file @ionic-native/file-path @ionic-native/transfer sudo ionic cordova plugin add cordova-plugin-camera sudo ionic cordova plugin add cordova-plugin-file sudo ionic cordova plugin add cordova-plugin-file-transfersudo ionic cordova plugin add cordova-plugin-filepath
5.2 Icon 本地存储的使用
https://ionicframework.com/docs/storage
1. 安装插件
ionic cordova plugin add cordova-sqlite-storage npm install --save @ionic/storage
2. src/app/app.module.ts导入配置
import { IonicStorageModule } from '@ionic/storage' ;@NgModule ({ declarations : [ ], imports : [ BrowserModule , IonicModule .forRoot (MyApp ), IonicStorageModule .forRoot () ], bootstrap : [IonicApp ], entryComponents : [ ], providers : [ ] }) export class AppModule {}
3. 在你的页面中使用
import { Storage } from '@ionic/storage' ;export class MyApp { constructor (private storage: Storage ) { } ... storage.set ('name' , 'Max' ); storage.get ('age' ).then ((val ) => { console .log ('Your age is' , val); }); }
5.3 二维码扫描
https://ionicframework.com/docs/native/qr-scanner
1. 安装插件
$ ionic cordova plugin add cordova-plugin-qrscanner $ npm install --save @ionic-native/qr-scanner
2. 在src/app/app.module.ts中导入
import { QRScanner , QRScannerStatus } from '@ionic-native/qr-scanner' ; providers : [ StatusBar , SplashScreen , {provide : ErrorHandler , useClass : IonicErrorHandler }, QRScanner ]
3. 在页面中使用
page -scan {html ,body ,ion-app, ion-content , ion-page , .nav-decor { background-color : transparent !important ; } .line { position : absolute; z-index : 999999 ; top : 15px ; height : 2px ; width : 100% ; background-color : #009900 ; animation : scan 1s infinite alternate; -webkit-animation : scan 1s infinite alternate; } @keyframes scan { from { top : 20% ; } to { top : 80% ; } } }
<ion-header > <ion-navbar > <ion-title > </ion-title > </ion-navbar > </ion-header > <div class ="line" > </div >
import { Component } from '@angular/core' ;import { IonicPage , NavController , NavParams , AlertController } from 'ionic-angular' ;import { QRScanner , QRScannerStatus } from '@ionic-native/qr-scanner' ;@Component ({ selector : 'page-scan' , templateUrl : 'scan.html' , }) export class ScanPage { constructor (public navCtrl: NavController, public navParams: NavParams, public alertCtrl: AlertController, public qrScanner: QRScanner ) { } ionViewDidLoad ( ) { console .log ('ionViewDidLoad ScanPage' ); } ionViewDidEnter ( ) { this .scanQRCode (); } scanQRCode ( ) { this .qrScanner .prepare () .then ((status: QRScannerStatus ) => { if (status.authorized ) { window .document .querySelector ('body' ).classList .add ('transparent-body' ); let scanSub = this .qrScanner .scan ().subscribe ((text: string ) => { let alert = this .alertCtrl .create ({ title : '二维码内容' , subTitle : text, buttons : ['OK' ] }); alert.present (); scanSub.unsubscribe (); }); this .qrScanner .show (); } else if (status.denied ) { } else { } }) .catch ((e: any ) => console .error ('Error :' , e)); } }
4. 调用scan页面
<button ion-item (click )="gotoScanQRCode()" > <ion-icon name ="qr-scanner" item-start color ="dark" > </ion-icon > <ion-label > 扫描二维码</ion-label > </button >
import { ScanPage } from '../scan/scan' ; constructor (public navCtrl: NavController, public navParams: NavParams ) { super () } gotoScanQRCode ( ) { this .navCtrl .push (ScanPage , null , {'animate' : false }) }
5.4 读取版本信息
https://ionicframework.com/docs/native/app-version
1. 安装插件
$ ionic cordova plugin add cordova-plugin-app-version $ npm install --save @ionic-native/app-version
导入app.module.ts
import { AppVersion } from '@ionic-native/app-version' ;providers : [ AppVersion ]
2. 新建一个页面展示version
3. 在app.modules.ts中导入
4. version页面配置
在浏览器中不可以调试,需要真机调试
<ion-header > <ion-navbar > <ion-title > 版本信息</ion-title > </ion-navbar > </ion-header > <ion-content > <ion-list > <ion-item > AppName: {{appName}} </ion-item > <ion-item > PackageName: {{packageName}} </ion-item > <ion-item > VersionCode: {{versionCode}} </ion-item > <ion-item > VersionNumber: {{versionNumber}} </ion-item > </ion-list > </ion-content >
import { Component } from '@angular/core' ;import { IonicPage , NavController , NavParams } from 'ionic-angular' ;import { AppVersion } from '@ionic-native/app-version' ;@Component ({ selector : 'page-versions' , templateUrl : 'versions.html' , }) export class VersionsPage { appName : string; packageName : string; versionCode : string; versionNumber : string; constructor (public navCtrl: NavController, private appVersion: AppVersion, public navParams: NavParams ) { } ionViewDidLoad ( ) { this .appVersion .getAppName ().then (v => { this .appName = v; }); this .appVersion .getPackageName ().then (v => { this .packageName = v; }); this .appVersion .getVersionCode ().then (v => { this .versionCode = v; }); this .appVersion .getVersionNumber ().then (v => { this .versionNumber = v; }); } }
5. 其他组件中使用
<button ion-item (click )="gotoVersions()" > <ion-icon name ="help-circle" item-start color ="dark" > </ion-icon > <ion-label > 关于</ion-label > </button >
gotoVersions ( ){ this .navCtrl .push (newPage) }
六、页面之间的传参 6.1 js跳转方式
路由跳转通过NavController
1. 导入NavController
import { NavController } from 'ionic-angular' ;
2. 注入
constructor (public navCtrl: NavController ) {}
3. 传参
this .navCtrl .push (DetailsPage , {id : questionId})
navCtrl传参和ModalCtr传参一样
this .ModalCtrl .create (AnswerPage , { id : this .id })
4. 接收参数
public id :string; constructor (public navCtrl: NavController, public navParams: NavParams ) { this .id = navParams.get ('id' ) } ionViewDidLoad ( ){ this .id = this .navParams .get ('id' ) }
6.2 HTML传参 1. 传参
通过[navPush]打开新页面,[navParams]传递参数。navPush文档
import { ChatdetailsPage } from '../chatdetails/chatdetails' public ChatdetailsPage : any; constructor ( ){ userinfo = { userId : '1234' , username : 'poetries' } this .ChatdetailsPage = ChatdetailsPage ; }
<ion-item [navPush ]="ChatdetailsPage" [navParams ]="userinfo" > <ion-avatar > <img src ="https://blog.poetries.top/images/avatar.jpg" > </ion-avatar > <h2 > poetries</h2 > <p > 聊天组件开发</p > </ion-item >
2. 获取传递的参数
constructor (public navCtrl: NavController, public navParams: NavParams ) { this .username = navParams.get ('username' ) this .userid = navParams.get ('userid' ) }
七、管道的使用 1. 新建管道
ionic g pipe realativetime # 管道名称
2. 配置
import { Pipe , PipeTransform } from '@angular/core' ;import * as moment from 'moment' @Pipe ({ name : 'relativetime' , }) export class RelativetimePipe implements PipeTransform { transform (value: string, ...args ) { return moment (value).toNow () } }
3. src/App/modules.ts中全局导入
import { RelativetimePipe } from '../pipes/relativetime/relativetime' @NgModule ({ declarations : [ RelativetimePipe ] ...
4. 使用
<div class ="msg-info" > <p > {{msg.username}} {{msg.time | relativetime}}</p > </div > ``` # 八、Theme主题全局样式 ## 8.1 全局图标颜色配置 **1. `theme/variables.scss`中定义** ```scss $colors: ( primary: #488aff, /**蓝色。优先匹配**/ secondary: #32db64, /**第二匹配**/ danger: #f53d3d, /**第三匹配**/ light: #f4f4f4, dark: #222 );
2. 使用
<ion-icon name ="paper" item-start color ="primary" > </ion-icon >
8.2 自定义样式
定义两套样式
在theme中新建light.scss。在variables.scss中导入
8.3 全局设置夜间模式切换 **1. 在theme中新建theme.dark.scss。在variables.scss中导入 **
.dark-theme { ion-content ,.card ,.floatMenu { background-color : #1e2446 !important ; color : #fff !important ; } .toolbar-title { color : #fff !important ; } .header .toolbar-background { border-color : #140414 !important ; background-color : #3a3c4b !important ; } .list ,.label ,.item { background-color : #3a3c4b !important ; color :#FFFFFF !important ; } .item { border-bottom : 0.55px solid #2e2749 !important ; } .item-inner ,{ border : none !important ; } .item-block { border-bottom : 0.55px solid #2e2749 !important ; } }
2. 在theme中新建theme.light.scss。在variables.scss中导入
.light-theme { ion-content { background-color : #e3e4e7 } .toolbar-background { background-color : #fff ; } }
3. 在variables.scss中导入
@import "theme.light" ;@import "theme.dark" ;
<ion-list class ="marginTop" > <ion-list-header > 设置 </ion-list-header > <ion-item > <ion-icon name ="cloudy-night" item-start color ="purple" > </ion-icon > <ion-label > 夜间模式</ion-label > <ion-toggle color ="purple" (ionChange )="toggleChangeTheme()" > </ion-toggle > </ion-item > </ion-list >
4. 新建一个provider来控制app主题的切换
import { HttpClient } from '@angular/common/http' ;import { Injectable } from '@angular/core' ;import { BehaviorSubject } from 'rxjs/Rx' @Injectable () export class SettingsProvider { private theme : BehaviorSubject <string> constructor (public http: HttpClient ) { this .theme = new BehaviorSubject ('light-theme' ) } setActiveTheme (val ) { this .theme .next (val) } getActiveTheme ( ) { return this .theme .asObservable () } }
5. 在app.component.ts中设置
然后在src/app/app.html中设置selectedTheme
<ion-nav [root ]="rootPage" [class ]="selectedTheme" > </ion-nav >
6. 在对应组件页面中设置
import { SettingsProvider } from '../../providers/settings/settings' ;export class UserCenterPage { public selectedTheme : string; constructor (public navCtrl: NavController, public navParams: NavParams, public settings: SettingsProvider public ModalCtrl: ModalController ) { super () this .settings .getActiveTheme ().subscribe (val => this .selectedTheme = val) } toggleChangeTheme ( ) { if (this .selectedTheme == 'dark-theme' ) { this .settings .setActiveTheme ('light-theme' ) }else { this .settings .setActiveTheme ('dark-theme' ) } } }
7. 在整个app启动的时候设置夜间或者白天模式
九、组件化开发-自定义组件 9.1 自定义组件 1. 新建组件
ionic g component emojipicker# 组件名称
2. 在src/app/app.module.ts中导入
import { ComponentsModule } from '../components/components.module' @NgModule ({ declarations : [ ], imports : [ BrowserModule , HttpClientModule , ComponentsModule , IonicStorageModule .forRoot () ], bootstrap : [IonicApp ], entryComponents : [ ], providers : [ StatusBar , SplashScreen , {provide : ErrorHandler , useClass : IonicErrorHandler } ] }) export class AppModule {}
3. 使用
在页面中使用即可
4. 组件通过@input()接收外部参数
4.1 定义组件
import { Component , Input } from '@angular/core' ;@Input ('dataType' ) dataSourceType; ngAfterContentInit ( ){ console .log (this .dataSourceType ) }
4.2 使用组件
<question-list dataType ="{{dataType}}" > </question-list >
9.2 [hidden] [style] [class] 动态控制组件 1. 动态显示隐藏hidden
<ion-content padding > <img src ="{{pathForImage(lastImage)}}" class ="img" [hidden ]="lastImage === null" /> <h3 [hidden ]="lastImage !== null" > 请从图片库选择一个图片</h3 > </ion-content >
2. 动态绑定style
<ion-footer no-border [style.height ]="isOpenEmojiPicker ? '255px': '55px' " > </ion-footer >
3. 动态绑定class属性
<div class ="message right" *ngFor ="let msg of messageList" [class.right ] = "msg.userId === userId" [class.left ] = "msg.userId === chatUserId" > </div >
十、指令
采用了angular语法 建议参考这篇文章
十一、常用组件使用
组件文档 https://ionicframework.com/docs/components
11.1 ModalController/LoadingController/ToastController 1. 导入
import {ModalController , LoadingController , ToastController , ViewController } from 'ionic-angular' ;
2. 注入
constructor ( public loadingCtr: LoadingController, public viewCtr: ViewController, public toastCtrl: ToastController, public ModalCtrl: ModalController ) { }
3. 使用
let loader = loadingCtr.create ({ content : message, dismissOnPageChange : true }) loader.present () loading.dismiss () let toast = toastCtrl.create ({ message, duration : 3000 , position : 'bottom' }) toast.present () let modal = this .ModalCtrl .create (QuestionPage ) modal.present () modal.onDidDismiss (()=> { this .loadPage () }) this .viewCtr .dismiss ()
4. 封装loading, toast
import { Loading , LoadingController , ToastController , Toast } from 'ionic-angular' ;export abstract class BaseUI {constructor ( ) {} protected showLoading (loadingCtr : LoadingController , message : string): Loading { let loader = loadingCtr.create ({ content : message, dismissOnPageChange : true }) loader.present () return loader } protected showToast (toastCtrl : ToastController , message : string):Toast { let toast = toastCtrl.create ({ message, duration : 3000 , position : 'bottom' }) toast.present () return toast } }
import { Component } from '@angular/core' ;import { ModalController , LoadingController , ToastController } from 'ionic-angular' ;import { ApiProvider } from '../../providers/api/api' import { BaseUI } from '../../common/baseui' @Component ({ selector : 'page-home' , templateUrl : 'home.html' }) export class HomePage extends BaseUI { feeds : string[]; errorMessage : string; constructor ( public loadingCtr: LoadingController, public api: ApiProvider, public toastCtrl: ToastController, public ModalCtrl: ModalController ) { super () } getFeeds ( ) { let loading = super .showLoading (this .loadingCtr , '加载中...' ) this .api .getFeeds ().subscribe (data => { if (data['UserId' ]) { this .feeds = data loading.dismiss () }else { super .showToast (this .toastCtrl , data['StatusContent' ]) } },err =>this .errorMessage = <any>err) } }
11.2 Refresh组件
刷新组件
<ion-content > <ion-refresher (ionRefresh )="doRefresh($event)" > <ion-refresher-content pullingIcon ="arrow-down" pullingText ="下拉刷新" refreshingSpinner ="circles" refreshingText ="数据加载中..." > </ion-refresher-content > </ion-refresher > <ion-card *ngFor ="let q of questions" (click )="gotoDetails(q.IdentityId)" > <ion-item > <ion-avatar item-start > <img src ="{{q.HeadFace}}" > </ion-avatar > <p > {{q.UserNickName}}发布了该问题 <ion-icon class ="more-button" name ="more" > </ion-icon > </p > </ion-item > <h2 > {{q.ContentTitle}}</h2 > <ion-card-content > <p > {{q.ContentSummary}}</p > </ion-card-content > <ion-row > <ion-col col-8 center text-left > <ion-note > {{q.LikeCount}} 赞同 . {{q.CommentCount}} 评论 . 关注 </ion-note > </ion-col > <ion-col col-4 > </ion-col > </ion-row > </ion-card > </ion-content >
doRefresh (refresher ) { this .getQuestions () refresher.complete () }
11.3 List组件
https://ionicframework.com/docs/components/#lists
https://ionicframework.com/docs/components/#buttons
11.5 card组件
https://ionicframework.com/docs/components/#cards
<ion-card *ngFor ="let f of feeds" (click )="gotoDetails(f.IdentityId)" > <ion-item > <ion-avatar item-start > <img src ="{{f.HeadFace}}" > </ion-avatar > <p > {{f.UserNickName}}回答了该问题 <ion-icon class ="more-button" name ="more" > </ion-icon > </p > </ion-item > <h2 > {{f.ContentTitle}}</h2 > <ion-card-content > <p > {{f.ContentSummary}}</p > </ion-card-content > <ion-row > <ion-col col-8 center text-left > <ion-note > {{f.LikeCount}} 赞同 . {{f.CommentCount}} 评论 . 关注 </ion-note > </ion-col > <ion-col col-4 > </ion-col > </ion-row > </ion-card >
11.6 表单组件
https://ionicframework.com/docs/components/#inputs
十二、Ionic打包上线流程 12.1 图标生成
替换resource/icon.png图标为1024*1024
生成图标
第一次生成,需要注册账号才可生成 https://dashboard.ionicframework.com/signup
生成图标的过程可能需要翻墙
12.2 启动图生成
替换resource/splash.png图标为1024*1024
# 在项目根目录执行 不需要进到resources文件夹 ionic cordova resources
12.3 打包前细节处理
修改index.html中的title
修改config.xml 中的信息
widget id="io.ionic.starter" version="0.0.1" 修改id(包名)以及version
<name>MyApp</name> 修改app名字
<description>An awesome Ionic/Cordova app.</description> 修改app描述
<author email="hi@ionicframework" href="http://ionicframework.com/">Ionic Framework Team</author> 修改email
12.4 打包部署
项目文件夹需要执行权限
sudo chomd 777 your_project_name
打开xcode进行ios下的调试
12.5 上架流程 12.5.1 IOS的打包
app store上架,需要注册开发者账号
12.5.2 安卓版本打包
最后生成apk文件。
打包方式
通过Android studio生成
通过命令生成
1. 需要安装jdk环境,并设置环境变量
2. 配置Gradle
platforms/android/cordova/lib/builders/GradleBuilder.js
找到distributionUrl
var distributionUrl = process.env ['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL' ] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip' ;
var distributionUrl = process.env ['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL' ] || '../gradle-4.1-all.zip' ;
3. 配置Gradle的环境变量
第一步
把上一步下载的Gradle把放到任意目录,这里我放的路径/Users/poetry/cordova/gradle-4.1
第二步: 新增环境变量
在mac下编辑.bash_profile配置文件, sudo vi ~/.bash_profile。新增一个环境变量,这里的$HOME就是/Users/poetry路径
第三步: 使环境变量生效
sudo vi ~/.zshrcsource .bash_profile
第四步:新开一个终端
第五步:测试
4. debug测试版打包
查看当前打包环境ionic info
Ionic: ionic (Ionic CLI) : 4.7.1 Ionic Framework : ionic-angular 3.9.2 @ionic/app-scripts : 3.2.1 Cordova: cordova (Cordova CLI) : 8.1.2 (cordova-lib@8.1.1) Cordova Platforms : android 7.1.4, browser 5.0.4, ios 4.5.5 Cordova Plugins : cordova-plugin-ionic-webview 1.2.1, (and 11 other plugins) System: Android SDK Tools : 26.1.1 NodeJS : v9.10.0 npm : 5.6.0 OS : macOS Mojave Xcode : Xcode 10.1 Build version 10B61
注意:需要前面几步环境配置好了,才可以正常执行打包
打包后输出apk路径 platforms/android/app/build/outputs/apk/debug/
生成的apk。此时可以把apk,拖入Genymotion模拟器调试
5. 正式版本打包
5.1 未签名版本
此时打包的apk是没有签名的版本,不可以在手机上安装
ionic cordova build android --release
打包后输出apk路径 platforms/android/app/build/outputs/apk/release
在手机安装示意图,签名版不能安装
5.2 签名版本apk打包
签名步骤
1. 创建私钥,项目根目录下执行命令(记住设置的别名)
keytool -genkey -v -keystore [自定义秘钥文件名,如 my-app].jks -keyalg RSA -keysize 2048 -validity 36500 -alias [自定义app别名,如 my-alias]
-genkey 意味着执行的是生成数字证书操作
v 表示将生成证书的详细信息打印出来,显示在dos窗口中
-keyalg RSA 表示生成密钥文件所采用的算法为RSA
-validity 36500 表示该数字证书的有效期为36500天
2. 接下来会让设置秘钥库口令(记住秘钥):
秘钥库就是你的密码
3. 设置秘钥库口令后会让输入一些APP信息
4. 按照提示依次输入后会在你的项目根目录生成秘钥文件 my-app.jks
把之前生成好的platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk复制到项目根目录,这样和my-app.jks同一目录签名
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore [上步生成的xxx.jks] app-release-unsigned.apk [步骤1命令中设置的app别名,如 my-alias]
keytool -genkey -v -keystore my-app.jks -keyalg RSA -keysize 2048 -validity 36500 -alias my-app
5. 验证应用是否签名成功
jarsigner -verify -verbose -certs 你的apk名
jarsigner -verify -verbose -certs app-release-unsigned.apk
5. 优化 apk 文件
5.1 首先需要配置环境变量
vi ~/.bash_profile export PATH=$PATH :$ANDROID_HOME /build-tools/27.0.3/Users/poetry/Library/Android/sdk/build-tools/27.0.3/zipalign source ~/.bash_profilevi ~/.zshrc source .bash_profilezipalign -v
5.2 在项目根目录执行
zipalign -v 4 app-release-unsigned.apk ionicQa.apk
6. 遇到的问题
6.1 无法打开 jar 文件
将 秘钥文件 xxx.jks 与 android-release-unsigned.apk 放在同一目录下,放到项目根目录就好了
此时就构建好了应用,这里是构建的应用
12.5.3 网站微信端发布
打包成一个静态站点方便部署
静态网站部署的站点资源路径 platform/browser/www
十三、一些问题记录 13.1 问题 1. 【ionic3】刷新页面,ws中断
解决办法升级@ionic/app-scripts
npm install @ionic/app-scripts@latest --save-dev
13.2 技巧 读取可空对象
question?.ContentTitle question可能返回空
十四、更多参考 14.1 项目学习
https://github.com/poetries/ionic-qa-app
14.2 文档参考