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 系统中起作用

posted @ 2017-01-14 19:47  不如隐茶去  阅读(3149)  评论(0编辑  收藏  举报