Angular2 + NativeScript 跨平台開發筆記(一)


NativeScript 是一款跟 ReactNative 對着懟的移動開發技術,其官方欽定了 Angular2 作為推薦的技術框架,那么如何讓在瀏覽器中運行的 Angular2 Web app 項目與 NativeScirpt 項目共享代碼呢?

安裝 git

git 是一個好東西,讓我們首先來安裝他,但與以往的安裝方式稍有不同。
以下內容 linuxer 可以忽略
進入 git 官網,下載最新的 git for windows 客戶端 https://git-scm.com/
安裝過程大多可以無腦下一步,但是在下面的頁面中,要注意一下,勾上Enable symbolic links

image_1b6e8f1hm6r8issb4i9s9vp09.png-29.8kB

創建項目倉庫

使用 git init 初始化項目倉庫,然后編輯 .git/config 文件,將 symlinks=false 改成 symlinks=true

建立項目

使用 angular-cli 與 nativescript-cli 創建項目,建立項目沒有特別的地方,安裝cli 的說明建立即可,使目錄結構如圖所示:

│  .gitignore
│      
├─mobile
│  │  package.json
│  │  references.d.ts
│  │  tsconfig.json
│  │  
│  ├─app
│  │
│  ├─hooks
│  │          
│  ├─node_modules
│  │                  
│  └─platforms
│                              
└─web
    │  .editorconfig
    │  angular-cli.json
    │  karma.conf.js
    │  package.json
    │  protractor.conf.js
    │  README.md
    │  tslint.json
    │  
    ├─e2e
    │      
    ├─node_modules
    │
    └─src

建立共享代碼文件夾

在 web/src/app 中建立 x-shared 文件夾,表示 cross-platform-shared 的意思。
然后,cd 到 mobile/app 文件夾中,以管理員身份運行命令行(cmd)並輸入:

mklink /d x-shared ..\..\web\src\app\x-shared

這樣我們就使用軟鏈接建立一個共享文件夾
linuxer 請使用 ln 命令建立軟鏈接

然后在任意一個 x-shared 文件夾中建立需要跨平台共享的代碼文件,比如負責 http 請求的 service,這里我來做個示例:

// account.service.ts

import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Injectable } from '@angular/core';

// rxjs
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

import { LoginResult } from '../models/login-result';
import { ErrorJson } from '../models/error';
import { Config } from '../config';


@Injectable()
export class AccountService {
    private loginUrl = Config.baseUrl + 'api/account/login';

    /**
     * 登錄!
     */
    constructor(private http: Http) {
    }

    /**
     * 解析消息
     * 
     * @private
     * @param {Response} res
     * @returns {LoginResult}
     * 
     * @memberOf AccountService
     */
    private extractData(res: Response): LoginResult {
        let body = res.json();
        return <LoginResult>body;
    }

    /**
     * 錯誤處理,將錯誤消息返回,消息形式:錯誤代碼 - 錯誤詳情
     * 
     * @private
     * @param {(Response | any)} error
     * @returns
     * 
     * @memberOf AccountService
     */
    private errorHandler(error: Response | any) {
        let errMsg: string;
        if (error instanceof Response) {
            const body = <ErrorJson>error.json();
            errMsg = `${body.errorMsg}`;
        } else {
            errMsg = error.toString();
        }
        console.log('errMsg');
        return Observable.throw(errMsg);
    }

    /**
     * 用戶登錄
     * 
     * @param {string} usr 用戶名
     * @param {string} pwd 明文密碼
     * @returns 登錄結果
     * 
     * @memberOf AccountService
     */
    login(usr: string, pwd: string) {
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });

        let data = {
            userName: usr,
            password: pwd
        };

        return this.http.post(this.loginUrl, data, options)
            .map(this.extractData)
            .catch(this.errorHandler);
    }
}

然后分別在兩個項目中引用這個 service。

調用共享的 Service

就像原先一樣來引用共享的 service

// web 版的登錄入口

import { Component, OnInit } from '@angular/core';

import { AccountService, LoginResult, ErrorJson } from 'x-shared'; // 就像原先一樣來引用共享的 service

import { LocalNoticeService, LocalNoticeType } from 'shared/notice.service';

@Component({
    selector: 'nav-account',
    templateUrl: './nav-account.component.html',
    styleUrls: ['./nav-account.component.css'],
    providers: [AccountService]
})
export class NavAccountComponent implements OnInit {

    constructor(
        private account: AccountService,
        private localNoticeService: LocalNoticeService // 這是在網頁彈窗的消息服務
    ) {
    }

    login(usr: string, pwd: string) {
        if (usr === '' || pwd === '') {
            // 在網頁上顯示一個提醒
            this.localNoticeService.showMsg('登錄失敗', '請輸入用戶名和密碼!', LocalNoticeType.error);
            return;
        }
        // 跨平台的登錄功能
        this.account.login(usr, pwd)
            .subscribe(
            (res: LoginResult) => {
                this.localNoticeService.showMsg('登錄成功', '', LocalNoticeType.success);
            },
            (error: string) => {
                this.localNoticeService.showMsg('登錄失敗', error, LocalNoticeType.error);
            });
    }

    ngOnInit() { }
}
// 手機上面的登錄頁面

import { Component, OnInit } from '@angular/core';
import * as dialogs from 'ui/dialogs';

import { AccountService, LoginResult } from '../../x-shared'; // 就像原先一樣來引用共享的 service

@Component({
    selector: 'login',
    templateUrl: './pages/login/login.component.html',
    providers: [AccountService]
})

export class LoginComponent implements OnInit {

    constructor(private account: AccountService) { }

    ngOnInit() { }

    login(usr: string, pwd: string) {
        if (usr === '' || pwd === '') {
        // 調用原生的 API 彈窗提示
            dialogs.alert({
                message: '請填寫用戶名和密碼!',
                okButtonText: '確定'
            });
            return;
        }
        // 跨平台的登錄功能
        this.account.login(usr, pwd)
            .subscribe(
            (res: LoginResult) => {
                let options: dialogs.AlertOptions = {
                    title: '登陸成功',
                    message: `${res.token.authToken}
                    ${res.token.refreshToken}`,
                    okButtonText: '確定'
                };
                dialogs.alert(options).then(() => console.dir(res));
            },
            (err: string) => {
                let options: dialogs.AlertOptions = {
                    title: '登陸失敗',
                    message: err,
                    okButtonText: '確定'
                };
                dialogs.alert(options);
            });
    }
}

效果!
web 網頁
web.gif-415kB

手機移動端
mobile.gif-594.5kB

至此,我們就實現了網頁版與手機客戶端共享一套代碼的功能,一旦 service 需要發生變動,只需要更改任意一個 x-shared 文件夾的代碼,更改就會同時作用到另一個項目上。

注意!

  • 在 windows10 創造者更新之前,創建軟鏈接需要管理員權限,請確保通過使用帶有管理員權限的命令行來克隆倉庫

  • windows 下的軟鏈接只在 Vista 以上的 windows 系統中起作用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM