序言:本文主要介紹了使用 Ionic 和 Cordova 開發混合應用時如何添加用戶身份認證。教程簡易,對於 Ionic 入門學習有一定幫助。因為文章是去年發表,所以教程內關於 Okta 的一些使用步驟不太准確,但是通過 Okta 的官網也可以找到對應的內容。另外,使用 npm 安裝 Ionic starter 模板可能會有安裝失敗的情況,建議不要在這方面浪費太多時間,可以直接在 Ionic 的 GitHub 倉庫 中下載 starter 模板。
原文:How to Sprinkle ReactJS into an Existing Web Application
譯者:nzbin
使用 Okta 和 OpenID Connect (OIDC),可以很輕松的在 Ionic 應用中添加身份認證,完全不需要自己實現。 OIDC 允許你直接使用 Okta Platform API 進行認證,本文的目的就是告訴你如何在一個 Ionic 應用中使用這些 API。我將演示如何使用 OIDC 重定向、Okta 的 Auth SDK 以及基於 Cordova 內嵌瀏覽器的 OAuth 進行登錄; 由於功能還在開發中,所以省略了用戶注冊。
為什么使用 Ionic?
Ionic 是一個用於開發原生及先進 web 應用的開源的移動端 SDK。它使用 Angular 和 Apache Cordova ,可以用 HTML、CSS、和 JavaScript 來開發移動應用。Apache Cordova 將 HTML 代碼嵌入到一個設備上的原生 WebView 中, 通過外部功能接口來訪問原生資源。你可能聽說過 PhoneGap —— 這是 Adobe Cordova 的商業版本。
Cordova 和 PhoneGap 允許你使用一套代碼開發多個平台的應用 (比如 Android 和 iOS) 。除此之外,應用程序和原生程序相差無盡並且和原生體驗一樣好。如果你需要開發原生功能,使用 web 技術是無法實現的,但是有些原生插件可以實現。 Ionic Native 是這些插件的精選集。
我第一次使用 Ionic 是在 2013 年底。當時我做的項目是開發一款原生應用,但是打算使用 HTML 來開發適配多個屏幕的應用,這樣 web 開發者也可以參與開發。我在 2014 年的三月寫了我的經歷。我喜歡使用 Ionic,我發現使用 Ionic 移植現有的應用程序更多的就是修改 HTML 和調整 CSS。
Ionic 2 在 一月份發布, 可以使用 Angular 開發 Ionic 應用。 Ionic 3 在 四月份發布,允許使用 Angular 4 進行開發。
**注意: ** "Angular" 是 Angular 2+ 的通用名稱。AngularJS 是 1.x 版本的名稱。之所以用 Angular 命名是因為在 2017 年的三月發布了 Angular 4 。可以查看 Branding Guidelines for Angular and AngularJS 了解更多信息。
本文會演示如何創建一個簡單的 Ionic 應用以及如何添加用戶身份認證。大多數的應用都需要身份認證,這樣才能知道用戶是誰。一旦 app 知道你的身份,它就可以保存你的信息及個性化的功能。
開始使用 Ionic
為了設置 Ionic 的開發環境,需要完成以下幾步:
- 安裝 Node.js
- 使用 npm 安裝 Ionic 和 Cordova:
npm install -g cordova ionic
創建一個 Ionic 應用
在 terminal 窗口中,使用以下命令創建一個新的應用程序:
ionic start ionic-auth
命令行會提示選擇一個 starter 項目並且可以選擇是否將應用連接到 Ionic Dashboard。對於本教程,選擇 tabs starter 項目,不需要將項目連接到 Ionic Dashboard。
項目創建需要花費一到兩分鍾,這取決於你的網絡連接速度。運行以下命令來打開你的 Ionic 應用。
cd ionic-auth
ionic serve
這個命令默認打開瀏覽器的 http://localhost:8100。你可以使用 Chrome 的設備模式查看應用程序在 iPhone 6 中的效果。
使用 Ionic serve
命令的特點是它會在瀏覽器中顯示編譯錯誤,而不是(有時會隱藏)在開發控制台。比如,給 app.component.ts
組件中的 rootPage
變量設置一個非法類型,你將看到以下錯誤。
添加用戶身份認證
Ionic Cloud 提供了免費的 Auth 服務。它允許使用郵箱及密碼驗證身份,也可以使用社交提供商比如 Facebook、Google 和 Twitter 登錄。你可以使用 @ionic/cloud-angular
依賴中提供的類創建身份認證。它也支持 自定義身份認證,但是 "需要你自己的服務器處理身份認證"。
目前還沒有太多關於這方面的教程,不過從去年開始有了一些。
- Simon Reimler's Simple Ionic 2 Login with Angular 2
- Raymond Camden's An example of the Ionic Auth service with Ionic 2
- Josh Morony's Using JSON Web Tokens (JWT) for Custom Authentication in Ionic 2: Part 2
你可能注意到所有的教程都需要很多的代碼。另外,關於如何在后端的 Auth 服務中驗證用戶身份的文檔也不多。
在 Okta 中創建 OpenID Connect 應用
OpenID Connect (OIDC) 基於 OAuth 2.0 協議。它允許客戶端驗證用戶的身份並獲得他們的基本配置文件信息。為了將 Okta 的身份認證平台整合到用戶身份認證中,需要以下步驟:
- 注冊 並創建一個 OIDC 應用
- 登錄 Okta 賬戶,然后導航到 Admin > Add Applications 並點擊 Create New App
- 選擇 Single Page App (SPA) 以及 OpenID Connect 作為登錄方式
- 點擊 Create 並給你的應用起個名字 (比如 "Ionic OIDC")
- 在下一頁上,添加
http://localhost:8100
作為重定向的 URI 並點擊 Finish。你會看到以下設置信息:
- 點擊 Assignments 標簽,然后選擇 Assign > Assign to People
- 給自己分配一個用戶,或者其它你授權的人。
創建登錄頁
為了創建身份認證的登錄頁,先創建 src/pages/login.ts
和 src/pages/login.html
。在 login.html
中,添加一個具有 username 和 password 的表單。
<ion-header>
<ion-navbar>
<ion-title>
Login
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<form #loginForm="ngForm" (ngSubmit)="login()" autocomplete="off">
<ion-row>
<ion-col>
<ion-list inset>
<ion-item>
<ion-input placeholder="Email" name="username" id="loginField"
type="text" required [(ngModel)]="username" #email></ion-input>
</ion-item>
<ion-item>
<ion-input placeholder="Password" name="password" id="passwordField"
type="password" required [(ngModel)]="password"></ion-input>
</ion-item>
</ion-list>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<div *ngIf="error" class="alert alert-danger">{{error}}</div>
<button ion-button class="submit-btn" full type="submit"
[disabled]="!loginForm.form.valid">Login
</button>
</ion-col>
</ion-row>
</form>
</ion-content>
你可以利用幾個開源庫來完成實際的身份驗證。第一個是 Manfred Steyer's angular-oauth2-oidc. 這個庫可以很容易的與 identity tokens 和 access tokens 交互。第二個是 Okta Auth SDK。由於 OIDC 和 OAuth 不是身份認證協議,所以這是使用 JavaScript 完成身份驗證所必需的,不必重定向到 Okta 。
使用 npm 安裝 angular-oauth2-oidc
npm install angular-oauth2-oidc --save
Okta Auth SDK 目前不支持 TypeScript,可以將以下代碼添加到 src/index.html
底部。
<script src="https://ok1static.oktacdn.com/assets/js/sdk/okta-auth-js/1.5.0/OktaAuth.min.js"></script>
在 src/pages/login/login.ts
中, 添加 LoginPage
類的基本結構,在構造器函數中使用 OAuthService
(來自於 angular-oauth2-oidc) 配置了 OIDC 的設置。 你需要使用 Okta OIDC 設置中的 Client ID 替換 "[client-id]" 以及你賬戶的當前 URI 替換 "[dev-id]"。
import { Component, ViewChild } from '@angular/core';
import { NavController } from 'ionic-angular';
import { OAuthService } from 'angular-oauth2-oidc';
declare const OktaAuth: any;
@Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
@ViewChild('email') email: any;
private username: string;
private password: string;
private error: string;
constructor(private navCtrl: NavController, private oauthService: OAuthService) {
oauthService.redirectUri = window.location.origin;
oauthService.clientId = '[client-id]';
oauthService.scope = 'openid profile email';
oauthService.oidc = true;
oauthService.issuer = 'https://dev-[dev-id].oktapreview.com';
}
ionViewDidLoad(): void {
setTimeout(() => {
this.email.setFocus();
}, 500);
}
}
修改 src/app/app.component.ts
驗證用戶是否登錄。如果沒有,將 LoginPage
設置為 rootPage。
import { OAuthService } from 'angular-oauth2-oidc';
import { LoginPage } from '../pages/login/login';
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage: any = TabsPage;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen,
oauthService: OAuthService) {
if (oauthService.hasValidIdToken()) {
this.rootPage = TabsPage;
} else {
this.rootPage = LoginPage;
}
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
});
}
}
更新 src/app/app.module.ts
,在 declarations
和 entryComponents
中添加 LoginPage
。你也要將 OAuthService
添加到 providers
中。
@NgModule({
declarations: [
...
LoginPage
],
...
entryComponents: [
...
LoginPage
],
providers: [
OAuthService,
...
]
})
運行 ionic serve
,確認 LoginPage
在 app 首次加載后可以展示出來。app 加載時會有以下報錯:
No provider for Http!
出現這個錯誤是因為 OAuthService
需要依賴 Angular 的 Http
模塊,但是還沒有將該模塊導入到項目中。在 src/app/app.module.ts
中導入 HttpModule
。
import { HttpModule } from '@angular/http';
@NgModule({
...
imports: [
BrowserModule,
HttpModule,
IonicModule.forRoot(MyApp)
],
...
})
現在登錄頁已經展示出來了。你可以使用 Chrome 的設備模式查看在 iPhone 6 上的效果。
為了解決缺少 TypeScript 支持的問題,你需要在 src/app/pages/login/login.ts
的頂部添加以下代碼。
declare const OktaAuth: any;
**TIP: ** 要了解更多關於在 TypeScript 項目引用外部 JavaScript 庫的知識,可以閱讀 Nic Raboy 寫的關於這方面的文章。
在 src/app/pages/login/login.ts
中添加一個 login()
方法,它使用 Okta Auth SDK 進行: 1) 登錄; 2) 將 session token 轉換成 identity 和 access token。 一個 ID token 類似於身份證,它是標准的 JWT 格式,由 OpenID 提供者簽名。Access tokens 是 OAuth 規范的一部分。一個 access token 可以是一個 JWT。它們用於訪問被保護的資源,通常是在發送請求時將它們添加到 Authentication
請求頭中。
login(): void {
this.oauthService.createAndSaveNonce().then(nonce => {
const authClient = new OktaAuth({
clientId: this.oauthService.clientId,
redirectUri: this.oauthService.redirectUri,
url: this.oauthService.issuer
});
authClient.signIn({
username: this.username,
password: this.password
}).then((response) => {
if (response.status === 'SUCCESS') {
authClient.token.getWithoutPrompt({
nonce: nonce,
responseType: ['id_token', 'token'],
sessionToken: response.sessionToken,
scopes: this.oauthService.scope.split(' ')
})
.then((tokens) => {
// oauthService.processIdToken doesn't set an access token
// set it manually so oauthService.authorizationHeader() works
localStorage.setItem('access_token', tokens[1].accessToken);
this.oauthService.processIdToken(tokens[0].idToken, tokens[1].accessToken);
this.navCtrl.push(TabsPage);
})
.catch(error => console.error(error));
} else {
throw new Error('We cannot handle the ' + response.status + ' status');
}
}).fail((error) => {
console.error(error);
this.error = error.message;
});
});
}
通過 identity token 你可以了解用戶的更多信息。通過 access token 你可以訪問需要 Bearer token 的受保護的 API。比如, 在 在 Angular PWA 中添加身份認證中,有一個 BeerService
,它用於在發送 API 請求時攜帶 access token 。
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs';
import { OAuthService } from 'angular-oauth2-oidc';
@Injectable()
export class BeerService {
constructor(private http: Http, private oauthService: OAuthService) {
}
getAll(): Observable<any> {
const headers: Headers = new Headers();
headers.append('Authorization', this.oauthService.authorizationHeader());
let options = new RequestOptions({ headers: headers });
return this.http.get('http://localhost:8080/good-beers', options)
.map((response: Response) => response.json());
}
}
您可以(可選)在表單上方添加圖標來美化登錄頁。下載 這張圖片,將它拷貝到 src/assets/image/okta.png
,在 login.html
的 <form>
標簽中添加以下代碼。
<ion-row>
<ion-col text-center>
<img src="assets/image/okta.png" width="300">
</ion-col>
</ion-row>
當你嘗試使用 Okta 的用戶證書登錄應用程序,你將在瀏覽器的控制台看到跨域報錯。
XMLHttpRequest cannot load https://dev-158606.oktapreview.com/api/v1/authn. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
為了修復這一問題,在 Okta 修改 Trusted Origins (在 Security > API 下面), 將你的 client's URL 添加進去 (比如 http://localhost:8100
)。檢查 CORS 和重定向的 origin 類型。
現在登錄可以正常工作了,但是 UI 界面並沒有提示。在首頁的右上角添加一個 "Logout" 按鈕。用以下 HTML 替換 src/pages/home/home.html
中的 <ion-header>
。
<ion-header>
<ion-navbar>
<ion-title>Home</ion-title>
<ion-buttons end>
<button ion-button (click)="logout()">
Logout
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
在 src/pages/home/home.ts
中,添加一個 logout()
方法, 用於在 identity token 中獲取姓名及 claims 。ID token 中的 claims 是關於頒發者、用戶、目標受眾、過期時間及頒發時間的信息。你可以閱讀 OIDC 規范中的標准 claims。
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { LoginPage } from '../login/login';
import { OAuthService } from 'angular-oauth2-oidc';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, public oauthService: OAuthService) {
}
logout() {
this.oauthService.logOut();
this.navCtrl.setRoot(LoginPage);
this.navCtrl.popToRoot();
}
get givenName() {
const claims = this.oauthService.getIdentityClaims();
if (!claims) {
return null;
}
return claims.name;
}
get claims() {
return this.oauthService.getIdentityClaims();
}
}
為了在 home 標簽頁上展示信息,將以下 HTML 添加到 src/app/home/home.html
文件的第二段之后。
<div *ngIf="givenName">
<hr>
<p>You are logged in as: <b>{{ givenName }}</b></p>
<div class="claims">
<strong>Claims from Identity Token JWT:</strong>
<pre>{{claims | json}}</pre>
</div>
</div>
更新 src/app/home/home.scss
,添加一些 CSS 讓原始的 JSON 看起來舒服一點。
page-home {
.claims {
pre {
color: green;
}
}
pre {
border: 1px solid silver;
background: #eee;
padding: 10px;
}
}
現在登錄之后你會看到你的姓名及聲明信息。
你可以退出之后看一下帶標識的登錄頁。
注意: 你可能注意到退出之后標簽頁並沒有消失。我正在查找 沒有正常工作 的原因。
發布到移動設備
使用 Ionic 在瀏覽器中開發移動應用是非常酷的事情。很高興你能看到自己的勞動成果以及優秀的手機應用。但是它的外觀和表現還不是原生應用。
為了查看應用程序在不同設備上的效果,你可以運行 ionic serve --lab
。--lab
標識會在瀏覽器中打開一個頁面讓你查看在不同設備中的效果。
LoginPage
在加載時會自動聚焦到 email
輸入框。為了自動激活鍵盤,你需要告訴 Cordova 沒有用戶交互的情況下顯示鍵盤是可以的。你可以在根路徑的 config.xml
中添加以下代碼。
<preference name="KeyboardDisplayRequiresUserAction" value="false" />
iOS
為了模擬或者部署到 iOS 設備上,你需要一個 Mac 以及一個新安裝的 Xcode。如果你喜歡在 Windows 中創建 iOS 應用,Ionic 提供了一個 Ionic Package 服務。
確保打開 Xcode 完成安裝 ,然后運行 ionic cordova emulate ios
在模擬器中打開應用。
可能會提示你安裝 @ionic/cli-plugin-cordova
插件。當出現提示時輸入 "y",按回車。
**TIP: ** 我發現在模擬器中運行應用程序時的最大問題是鍵盤很難彈出。為了解決這一問題,當我需要在輸入框輸入文本時,我使用 Hardware > Keyboard > Toggle Software Keyboard 。
如果你在登錄頁輸入憑證,可能什么也不會發生。打開 Safari 轉到 Develop > Simulator > MyApp / Login,你會看到控制台有一條錯誤信息。如果你看不到開發菜單,重新執行 這篇文章 中的方法使其生效。
如果打開 Network 標簽,你會看到只發送了一條請求 (to /authn
),它和在瀏覽器中發送的兩條請求 (to /authn
and /authorize
) 有所不同。
我相信使用 Cordova 打包 app 之后並不會正常工作,因為通過內嵌的 iframe 向服務端發送請求,然后使用 postMessage 將結果返回當前窗口。Ionic/Cordova 似乎並不支持這種方式。為了解決這個問題,你可以使用 Cordova 提供的 in-app 瀏覽器直接與 Okta 的 OAuth 服務通信。Nic Raboy 演示了在 Facebook 中的操作方法,他在 Ionic 2 移動 App 中使用了 OAuth 2.0 服務。
使用以下命令安裝 Cordova In-App Browser plugin :
ionic cordova plugin add cordova-plugin-inappbrowser
打開 src/app/pages/login/login.html
,用一個 <div>
包裹 <form>
,為了只在瀏覽器中運行時顯示登錄表單。添加一個新的 <div>
,它會在模擬器或設備上運行時顯示。
<ion-content padding>
<ion-row>
<!-- optional logo -->
</ion-row>
<div showWhen="core">
<form>
...
</form>
</div>
<div hideWhen="core">
<button ion-button full (click)="redirectLogin()">Login with Okta</button>
</div>
</ion-content>
打開 src/pages/login/login.ts
,在 imports 下面添加一個 window
的引用。
declare const window: any;
為了更容易的使用 OAuth 登錄,可以添加以下方法。
redirectLogin() {
this.oktaLogin().then(success => {
localStorage.setItem('access_token', success.access_token);
this.oauthService.processIdToken(success.id_token, success.access_token);
this.navCtrl.push(TabsPage);
}, (error) => {
this.error = error;
});
}
oktaLogin(): Promise<any> {
return this.oauthService.createAndSaveNonce().then(nonce => {
let state: string = Math.floor(Math.random() * 1000000000).toString();
if (window.crypto) {
const array = new Uint32Array(1);
window.crypto.getRandomValues(array);
state = array.join().toString();
}
return new Promise((resolve, reject) => {
const oauthUrl = this.buildOAuthUrl(state, nonce);
const browser = window.cordova.InAppBrowser.open(oauthUrl, '_blank',
'location=no,clearsessioncache=yes,clearcache=yes');
browser.addEventListener('loadstart', (event) => {
if ((event.url).indexOf('http://localhost:8100') === 0) {
browser.removeEventListener('exit', () => {});
browser.close();
const responseParameters = ((event.url).split('#')[1]).split('&');
const parsedResponse = {};
for (let i = 0; i < responseParameters.length; i++) {
parsedResponse[responseParameters[i].split('=')[0]] =
responseParameters[i].split('=')[1];
}
const defaultError = 'Problem authenticating with Okta';
if (parsedResponse['state'] !== state) {
reject(defaultError);
} else if (parsedResponse['access_token'] !== undefined &&
parsedResponse['access_token'] !== null) {
resolve(parsedResponse);
} else {
reject(defaultError);
}
}
});
browser.addEventListener('exit', function (event) {
reject('The Okta sign in flow was canceled');
});
});
});
}
buildOAuthUrl(state, nonce): string {
return this.oauthService.issuer + '/oauth2/v1/authorize?' +
'client_id=' + this.oauthService.clientId + '&' +
'redirect_uri=' + this.oauthService.redirectUri + '&' +
'response_type=id_token%20token&' +
'scope=' + encodeURI(this.oauthService.scope) + '&' +
'state=' + state + '&nonce=' + nonce;
}
把在構造器中設置的 redirectUri
替換成硬編碼 http://localhost:8100
。如果省略這一步,當 app 在設備上運行時, window.location.origin
會跳轉到 file://
。為了將它設置成已知的 URL,我們可以通過 in-app browser 的 "loadstart" 事件查找它。
constructor(private navCtrl: NavController, private oauthService: OAuthService) {
oauthService.redirectUri = 'http://localhost:8100';
...
}
更改之后,需要將 app 重新部署到手機上。
ionic cordova emulate ios
現在可以點擊 "Login with Okta" 按鈕,然后輸入合法的憑證進行登錄。
![]() |
![]() |
![]() |
使用這項技術的好處就是 Okta 的登錄頁具有“記住我”和“忘記密碼”的功能,所以不需要自己編寫代碼。
為了將 app 部署到 iPhone,首先將手機插到電腦上。然后運行以下命令安裝 ios-deploy、構建 app 並在你的設備上運行。
npm install -g ios-deploy
ionic cordova run ios
如果你之前沒有為應用程序設置代碼簽名,則此命令可能會失敗。
Signing for "MyApp" requires a development team. Select a development team in the project editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
在 Xcode 中打開你的項目,運行以下命令。
open platforms/ios/MyApp.xcodeproj
Ionic's 開發文檔 有解決這一問題的說明。
選擇你的手機作為 Xcode 的目標,然后點擊 play 按鈕運行 app。如果你是第一次做,Xcode 可能會加載一段時間,上方會顯示一條 "Processing symbol files" 的信息。
只要你已經設置了你的手機、電腦以及 Apple ID,你就可以打開應用並登錄。以下是在我的手機上的展示效果。
![]() |
![]() |
![]() |
Android
為了模擬或者部署到 Android 設備上,你首先要安裝 Android Studio。在安裝過程中,它會提示你將 Android SDK 安裝到哪里。將這個路徑設置為 ANDROID_HOME 的環境變量。在 Mac 上,it should be ~/Library/Android/sdk/
。
如果你已經安裝了Android Studio,請確保打開它以完成安裝。
為了部署到 Android 模擬器,運行 ionic cordova emulate android
。這個命令將安裝 Android 支持並打印關於如何創建模擬圖像的說明。
Error: No emulator images (avds) found.
1. Download desired System Image by running:
/Users/mraible/Library/Android/sdk/tools/android sdk
2. Create an AVD by running: /Users/mraible/Library/Android/sdk/tools/android avd
HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver
運行第一條建議並下載您想要的系統映像。然后運行第二個命令並用以下設置創建一個 AVD(Android 虛擬設備):
AVD Name: TestPhone
Device: Nexus 5
Target: Android 7.1.1
CPU/ABI: Google APIs Intel Axom (x86_64)
Skin: Skin with dynamic hardware controls
警告: 這些設置不適用於 Mac 上的 Android Studio 2.3.2 版本。當你嘗試運行第一條命令時,它會顯示以下內容:
*************************************************************************
The "android" command is deprecated.
For manual SDK, AVD, and project management, please use Android Studio.
For command-line tools, use tools/bin/sdkmanager and tools/bin/avdmanager
*************************************************************************
為了解決這個問題,打開 Android Studio,選擇 "Open an existing Android Studio project",然后選擇 ionic-auth/platforms/android
的路徑。如果提示升級,選擇 "OK",然后繼續創建一個新的 AVD ,和 Android Studio 文檔描述的那樣.
執行完這些步驟之后,你可以運行 ionic cordova emulate android
查看運行在 AVD 中的 app。
![]() |
![]() |
![]() |
注意: 如果應用程序顯示錯誤 "連接服務器失敗 (file:///android/www/index.html
)",在 config.xml
中添加以下代碼。這行代碼將默認超時時間設置為 60 秒 (默認 20)。感謝 Stack Overflow 社區 對此問題的解答。
<preference name="loadUrlTimeoutValue" value="60000"/>
使用 Ionic 開發 PWAs
Ionic 支持創建 progressive web apps (PWAs)。這意味着你可以將 Ionic app 部署成 web app (不是移動端 app) ,它可以在離線的 支持 service workers 的瀏覽器 中運行。
想要了解如何使用 service workers 並把 app 轉換成 PWA ,可以閱讀 如何使用 Ionic 和 Spring Boot 開發移動應用 的 PWAs 部分 。PWA 是可以安裝在系統中的 web 應用程序。它可以在離線情況下工作,使用的是你最后一次與 app 交互的數據緩存。添加 PWA 功能可以讓 app 加載更快,提供更好的用戶體驗。想要了解更多關於 PWA 的知識,可以閱讀 The Ultimate Guide to Progressive Web Applications.
了解更多
我希望你喜歡這篇關於 Ionic、Angular 及 Okta 的教程。我喜歡 Ionic 是因為它可以將你的 web 開發技能提升一個檔次,並且它可以快速創建仿原生的移動應用。
你可以在 GitHub 上查看本教程的完整代碼。如果你有問題,可以通過 Twitter @mraible 或者在 Okta's Developer Forums 上聯系我。
想要了解更多關於 Ionic、Angular 或者 Okta 的知識,可以查看以下資源: