NativeScript 是一款跟 ReactNative 对着怼的移动开发技术,其官方钦定了 Angular2 作为推荐的技术框架,那么如何让在浏览器中运行的 Angular2 Web app 项目与 NativeScirpt 项目共享代码呢?
安装 git
git 是一个好东西,让我们首先来安装他,但与以往的安装方式稍有不同。
以下内容 linuxer 可以忽略
进入 git 官网,下载最新的 git for windows 客户端 https://git-scm.com/
安装过程大多可以无脑下一步,但是在下面的页面中,要注意一下,勾上Enable symbolic links
。
创建项目仓库
使用 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 ....websrcappx-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 网页
手机移动端
至此,我们就实现了网页版与手机客户端共享一套代码的功能,一旦 service 需要发生变动,只需要更改任意一个 x-shared 文件夹的代码,更改就会同时作用到另一个项目上。
注意!
-
在 windows10 创造者更新之前,创建软链接需要管理员权限,请确保通过使用带有管理员权限的命令行来克隆仓库
-
windows 下的软链接只在 Vista 以上的 windows 系统中起作用