小型失物招领 App 客户端(iOS && 安卓)

项目说明

本身是搞 iOS 的后面入了 ReactNative 的坑,慢慢的就比较多的接触 JavaScript ,还有就是 JavaScript 慢慢的可以做的东西越来越多;
不仅可以做前端网页,还可以做移动端 App(ReactNative),还能做后端(Node.js),还有其他的;

这个 App 是为了搭配小型失物招领后端所做的,同时也使用了 redux react-navigation 等的做数据管理以及路由切换;

目前主要的 Feature:

  1. 用户登录注册;
  2. 基本的管理员权限管理;
  3. 失物招领信息发布,关注收藏,通知审核等;
  4. 管理员的基本功能的管理与审核;
  5. 极光推送对接,使内容实时推送给用户;

本地运行条件

  • 需要相应后端服务开启,本地 server 服务或者线上 server,下面会有相应的配置说明;

下载体验

iOS 没有发布,下载安卓体验

安卓 fir.im 下载

或者直接扫码下载

扫码下载

基础配置

  • 代码热更新配置(可不配置);

iOS
Android

  • 极光推送 appkey 配置

iOS
Android

  • 后端服务器地址配置

把在相应的服务地址填入对应环境中,设置 SET_ENV DEV 为开发地址 APP 为线上地址

config

仓库地址

服务器地址 GitHub 地址,具体配置看文档

App 地址,具体配置看文档

个人博客

博客地址: https://cblog.ferryvip.com/

小型失物招领后端(Express 版本)

项目说明

本身是搞 iOS 的后面入了 ReactNative 的坑,慢慢的就比较多的接触 JavaScript ,还有就是 JavaScript 慢慢的可以做的东西越来越多;
不仅可以做前端网页,还可以做移动端 App(ReactNative),还能做后端(Node.js),还有其他的;

这个失物招领是为了练手 Node.js,同时也为了配合这个写了个 App 前端(iOS 和 安卓),链接在后面也会放出了;

目前主要的 Feature:

  1. 用户登录注册;
  2. 基本的管理员权限管理;
  3. 失物招领信息发布,关注收藏,通知审核等;
  4. 管理员的基本功能的管理与审核;
  5. 极光推送对接,使内容实时推送给用户;

本地运行条件

  • MongoDB 数据库
  • Node.js 环境

基础配置

  1. 七牛配置
    1. 七牛配置是为了保存图片到七牛;
    2. 申请相应的开发者账号,填入到 config文件夹的config文件;
    3. 配置错误,或未配置调用到会导致程序崩溃;


  1. 极光配置
    1. 使消息即使让用户知道;
    2. 申请相应的开发者账号,填入到 config文件夹的config文件;
    3. 配置错误,或未配置调用到会导致程序崩溃;

造一些假数据的

项目目录下执行 node data.js 两次就行;

1
2
3
4
超级管理员
用户名: admin@163.com
密码: 123456
其他的用户: user[1 - 10]@163.com 密码: 123456

启动

  • 本地启动

    1. 首先启动本地 MongoDB 数据库,项目目录下执行 npm run mongo 数据库跑默认的段口;
    2. 项目目录下执行 npm start 启动;
    3. 就可以打开文档 http://localhost:5566/docs
  • 服务器部署(主要使用 pm2 部署)

    1. 服务器安装 node pm2 MongoDB 环境等;
    2. 项目目录下执行
      1. 测试 pm2 start dev.json
      2. 正式 pm2 start dev.json
    3. 查看日志 pm2 logs

对应的客户端

  • 目前就只做了 App 端,按理说目前接口基本可以做个网页前端的,微信公众号以及小程序,在做些修改也是应该可以的;

下载体验

iOS 没有发布,下载安卓体验

安卓 fir.im 下载

或者直接扫码下载

扫码下载

仓库地址

服务器地址 GitHub 地址,具体配置看文档

App 地址,具体配置看文档

个人博客

博客地址: https://cblog.ferryvip.com/

起因

最近用着钉钉,突然发现有个神奇的功能叫 Webhook 机器人,里面有 Github 的机器人,然鹅竟然没有我一直在用的 Coding.net 的机器人,这个不能忍,本着程序员自己动手丰衣足食的勤劳准则,想着就自己折腾弄一个玩玩;

因为自己只会点 Node.js 所以就做了个包,具体的看下面;

效果图

准备工作

找了一下两家的文档

Coding Webhook 文档

钉钉自定义机器人文档

大概原理就是,钉钉提供一个发送消息的 Webhook 地址给你,然后 Coding 家提供了一个给你填入 Webhook 的地址接口,当仓库有信息变化,就会给你这个地址接口发消息;然而钉钉没有做这个 Coding 的接口,所以不能提供 Coding 直接把消息发到钉钉上,所以只能自己搭个服务器,先把 Coding 的消息解析一下,在发给钉钉.基本原理就是这样,说的有点乱,哈哈;

服务器

设置 Webhook 路由;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const express = require('express'),
bodyParser = require('body-parser'),
CWD = require('./../index'),
app = express();

// 一般都会设置 bodyParser ,需要用到;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());


// 设置 Webhook 路由,已经中间件 CWD
app.post('/webhook', CWD());

app.listen(5566, function () {
console.log('Express server listening on port http://localhost:6666');
});

CWD 中间件;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
const request = require('request');
exports = module.exports = function (options) {
return function CodingHookDingDing (req, res, next) {
let event = req.headers['x-coding-event'],
body = req.body;
// 通过头文件的 event 事件判断传入的参数等,做相应的信息解析;
switch (event){
case "push":
return Push(req, res, next); // 对 push 做解析
case "ping":
return res.json({
"token": "123",
"zen": "Coding! 让开发更简单"
});
default:
return res.json(body);
}
};
};

function Push(req, res, next) {
/*-- 消息的解析拼接 --*/
let body = req.body;
let ding = body.token;
let count = body.commits.length;
let whopush = body.commits[0].committer.name;
let repourl = `${body.repository.owner.web_url}/p/${body.repository.name}/git/tree/${getbranch(body.ref)}`;
let branch = `# [[${body.repository.name}/${getbranch(body.ref)}]](${repourl})`;
let text = `${branch} ${count} commit,push by ${whopush}\n ## commits:\n`;
for (let i = 0; i < count; i++){
let com = body.commits[i];
let name = com.committer.name;
let mes = com.short_message;
let hash6 = com.sha.substring(0,6);
let commit = `> </> ${name}: [[${hash6}]](${com.web_url})-${mes}\n`;
text = text + commit;
}
console.log(text);
/*-- 消息的解析拼接 --*/

// 钉钉消息格式等 body 设置
let rqbody = {
msgtype: "markdown",
markdown: {
title:"仓库有新的代码更新咯!",
text: text
}
};

let options = {
url: ding,
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(rqbody) // 消息体内容
};
// request 向钉钉发送消息 Webhook
request.post(options, (err, res, body)=>{
if(!err && res.statusCode == 200){
let info = JSON.parse(body);
console.log(info);
}
});
res.json({mes: 'ok'});
}
function getbranch(str) {
let arr = str.split('/');
return arr[arr.length-1];
}

配置

1. 首先钉钉群里设置自定义机器人

1. 设置自定义机器人

2. 填入机器人名称

3. 复制 webhook 地址,后面有用

2. Coding 仓库 Webhook 设置

1. 点击到要设置的仓库 Webhook 页面,点击新建 Webhook

2. url 填入服务器上要监听的地址, token 填入刚才钉钉复制的 Webhook 地址,以及选取底部的监听类型,至少要勾选 Push

3. 如果配置顺利,在你以后每次仓库的变化,在钉钉上面都会收到消息提醒

npm 包

后面就干脆做了个 npm 包发布上去,目前只对 push 操作做消息发送,后续有时间在完善下其他操作;

安装

npm i --save hookding

使用方法

1
2
3
4
const CWD = require('hookding');

app.post('/router', CWD());

本文参与 Coding 征文计划

curl 基本使用

  1. 最简单的直接请求页面 curl "https://www.baidu.com"
  2. 请求保存页面 curl "https://www.baidu.com" > /path/name.html
  3. -o 保存页面 curl -o /path/name.html "https://www.baidu.com" --progress 显示进度条
  4. -s 加入这个就不会出现进度条,安静模式
  5. -A 参数用来指定 USER-AGENGT curl -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17" http://localhost/learing-curl/show-server-info.php
  6. -e 指定 referer 来源网址 curl -e "https://www.google.com/" http://localhost/learing-curl/show-server-info.php
  7. -d post 请求 curl -d "name=1" "http://localhost:6666/post"
  8. -G 轻质指定表单以 GET 方法提交
  9. -I 只展示 Header curl -I http://www.baidu.com
  10. -D 保存 Header 到文件里 curl -D header.txt http://www.alibaba.com
  11. -L 跟随重定向过去 curl -L http:localhost:6666/red
  12. -F 提交文件 curl -F upload_file=@test.data url
  13. -c 保存 cookie curl -c cookie.txt https://www.baidu.com
  14. -b 带 coolie 访问 curl -b "name=data" url curl -b cookie.txt url
  15. -H 设置请求头
  16. -m 设置最大传输时间 seconds
  17. -u 设置服务器用户名和密码 curl -u name:password url
1
2
3
4
5
6
7
8
curl 'https://oapi.dingtalk.com/robot/send?access_token=6fb5741248b308d1eb616f993fddf0fb3459f42cb6b4eb86078e33042b5bc4e0' \
-H 'Content-Type: application/json' \
-d \
'{"msgtype": "text",
"text": {
"content": "我就是我, 是不一样的烟火"
}
}'
1
2
3
4
5
6
curl 'http://www.ferryvip.com/v1/me/webhook' \
-H 'Content-Type: application/json ' \
-H 'x-coding-event: push ' \
-d \
'{"ref":"refs/heads/master","before":"fbec0e3aa41f1364587c5d62df9032bcc5406afd","commits":[{"committer":{"name":"chencangshan","email":"chencangshan@huaxiweiying.com"},"web_url":"https://coding.net/u/ferryVip/p/lostwebserver/git/commit/90360e33395e3bb1e1b844b4b85de08d2a559152","short_message":"测试 hook\n","sha":"90360e33395e3bb1e1b844b4b85de08d2a559152"}],"after":"90360e33395e3bb1e1b844b4b85ded2a559152","event":"push","repository":{"owner":{"path":"/u/ferryVip","web_url":"https://coding.net/u/ferryVip","global_key":"ferryVip","name":"ferryVip","avatar":"https://dn-coding-net-production-static.qbox.me/82b7ce57-96ef-4faf-a480-bb0645ab2a1a.jpg?imageMogr2/auto-orient/format/jpeg/crop/!200x200a0a0"},"https_url":"https://git.coding.net/ferryVip/lostwebserver.git","web_url":"https://coding.net/u/ferryVip/p/lostwebserver","project_id":"1219048","ssh_url":"git@git.coding.net:ferryVip/lostwebserver.git","name":"lostwebserver","description":"react webpack node mongodb express\n\n失物招领b server"},"user":{"path":"/u/ferryVip","web_url":"https://coding.net/u/ferryVip","global_key":"ferryVip","name":"ferryVip","avatar":"https://dn-coding-net-production-static.qbox.me/82b7ce57-96ef-4faf-a480-bb0645ab2a1a.jpg?imageMogr2/auto-orient/format/jpeg/crop/!200x200a0a0"},"token":"https://oapi.dingtalk.com/robot/send?access_token=6fb5741248b308d1eb616f993fddf0fb3459f42cb6b4eb86078e33042b5bc4e0"}'

ofo ReactNative 仿版(主要是做 iOS版本)

原因

之前一直想做个 ReactNative 关于地图相关的 demo ,然后近两天在群里看见有人发的 RN 做的 ofo 共享单车的仿版(主要是针对安卓的),就想着乘着这几天活不多,也做一个,用下最新的 RN 版本(0.44),本来是想体验一下一些新特性的,目前主要还是在40以下做项目,主要考虑版本兼容,不过目前看也差不多可以升级40以上了,至于这个 ofo 仿版还是有很多没有用到新的特性的东西,好了话不多说,上效果图;

效果图

iOS 安卓

package.json

1
2
3
4
5
6
7
8
9
10
"native-base": "^2.1.3",
"react": "16.0.0-alpha.6",
"react-native": "0.44.0",
"react-native-blur": "^3.0.0-alpha",
"react-native-camera": "^0.8.0",
"react-native-maps": "^0.15.0",
"react-native-scrollable-tab-view": "^0.6.6",
"react-native-share": "^1.0.20",
"react-native-simple-toast": "^0.0.6",
"react-navigation": "^1.0.0-beta.9"

主要用到的一些依赖,时间比较匆忙,有些没有兼容两个平台,特别是安卓,地图的没有做到很详细;

项目怎么跑起来

  1. 把本仓库下载或者克隆下来; Github 地址: https://github.com/strawferry/reactnativeofo
  2. 前往仓库目录,终端执行 npm install 或者 yarn;
  3. 终端执行 react-native link,链接相关的依赖;
  4. 然后运行项目;

感谢

当时在群里看到这个仓库,发现做的还不错,但是主要是针对安卓的,当时 iOS 适配比较差,就想着搞一个出来;
React Native 仿 ofo 共享单车 App http://www.marno.cn

最近一直在看一些关于持续集成的东西,持续集成会对整个项目的敏捷开发有很大的帮助;

了解过 jenkins, 功能非常强大,但是在做 iOS 持续集成必须在一台 Mac 系统下,后面通过了解和别人介绍,认识到了今天的主角 Travis CI;

hexo虽然可以方便地部署github静态博客,但是仅仅是把最终生成的html保存在repository中,像原始的Markdown文件,hexo配置文件,主题配置文件,修改文件都仅仅是保存在本地。这样不利于保存,也无法查看每篇博客的修改历史。更重要的是无法做到跨平台,也不易于多人写作。

想法是每次写博客,只需要push md文件及博客所需的资源文件即可。Travis CI持续集成tool可以满足此需求。

Travis CI 目前主要是和 GitHub 一起使用,所以今天的例子就以 hexo 博客的每次 push 触发 Travis CI 自动部署到 GitHub 的 Pages 上;

1. 思路

2. 具体实现

2.1 首先需要在 GitHub 上面创建一个仓库(或者已有)

以新建仓库为例

2.2 生成 Personal Access tokens

为后续的功能生成的 token

登录github, settings -> Personal access tokens -> Generate new token

填写token description,比如叫 travis.并勾选上授予的权限,比如我勾选的是repo和gist,然后create.

将产生的token串复制保留下来,后面会使用到,如果丢失,只能重新产生。

2.3 travis-ci 设置

登录 travis-ci 网站,利用 GitHub 账号登录;

同步 GitHub 仓库

选取刚才创建的仓库并打开

添加刚才的 token 作为全局变量

2.4 hexo 博客设置

基本的 hexo 命令

1
2
3
4
5
npm install hexo-cli -g
hexo init blog
cd blog
npm install
hexo server

进入 blog 所在的文件夹下,新建 .travis.yml 文件,并添加以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 使用语言
language: node_js
# node版本
node_js: stable
# 设置只监听哪个分支
branches:
only:
- source
# 缓存,可以节省集成的时间,这里我用了yarn,如果不用可以删除
cache:
apt: true
yarn: true
directories:
- node_modules
# tarvis生命周期执行顺序详见官网文档
before_install:
- git config --global user.name "name"
- git config --global user.email "mmail@mail.com"
# 由于使用了yarn,所以需要下载,如不用yarn这两行可以删除
- curl -o- -L https://yarnpkg.com/install.sh | bash
- export PATH=$HOME/.yarn/bin:$PATH
- npm install -g hexo-cli
install:
# 不用yarn的话这里改成 npm i 即可
- yarn
script:
- hexo clean
- hexo generate
after_success:
- cd ./public
- git init
- git add --all .
- git commit -m "Travis CI Auto Builder"
# 这里的 REPO_TOKEN 即之前在 travis 项目的环境变量里添加的
- git push --quiet --force https://$REPO_TOKEN@git@github.com/strawferry/FerryVipBlog.git master

然后,准备 push 该项目到 github ,如果是新项目可参照下面的git指令

1
2
3
4
5
6
7
8
git init
# 添加自己的项目
git remote add origin git@github.com:strawferry/travis.git
# 新建并切换分支
git checkout --orphan source
git add -A
git commit -m "init repo"
git push

2.5 发布博客文章

1
2
3
4
5
前往 source 分支下:
hexo new title // 1. 新建文章;
2. 使用 markdown 软件或者 vim 直接编写文章内容,并保存文件;
3. 把目前分支的内容变化提交到 git 线上仓库;
4. 接着就等待 travis-ci 自动部署到 pages 上;


这样你的博客就已经成功部署到 pages 上面了

总结

这个是一个简单的对 travis-ci 的入门,这样能够给我们提供不少的事,持续集成能够给开发带来极大的便利,让程序员不做一些重复的事情,提高效率;

pm2 node 服务器部署

安装

npm i -g pm2

启动服务

基本的 pm2 start app.js

带参数 pm2 ENV=production start app.js

从 .config.js 文件启动 pm2 start app.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports = {
apps : [{
name : "worker",
script : "./worker.js",
watch : true,
env: {
"NODE_ENV": "development",
},
env_production : {
"NODE_ENV": "production"
}
},{
name : "api-app",
script : "./api.js",
instances : 4,
exec_mode : "cluster"
}]
}

从 json 文件启动 pm2 start app.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"apps": [
{
"name": "lost100-dev",
"script": "./scripts/server.js",
"watch": true,
"ignore_watch": [ "node_modules", "files", "public", "logs", "mongodb", "build", ".idea/", ".git"],
"max_memory_restart": "150M",
"instances": 2,
"exec_mode": "cluster",
"env": {
"NODE_ENV": "dev",
"PORT": 5566
}
}
]
}

可用的参数详情

General

Field Type Example Description
name (string) “my-api” application name (default to script filename without extension)
script (string) ”./api/app.js” script path relative to pm2 start
cwd (string) “/var/www/” the directory from which your app will be launched
args (string) “-a 13 -b 12” string containing all arguments passed via CLI to script
interpreter (string) “/usr/bin/python” interpreter absolute path (default to node)
interpreter_args (string) ”–harmony” option to pass to the interpreter
node_args (string) alias to interpreter_args

Advanced features

Field Type Example Description
instances number -1 number of app instance to be launched
exec_mode string “cluster” mode to start your app, can be “cluster” or “fork”, default fork
watch boolean or [] true enable watch & restart feature, if a file change in the folder or subfolder, your app will get reloaded
ignore_watch list [”[/\]./”, “node_modules”] list of regex to ignore some file or folder names by the watch feature
max_memory_restart string “150M” your app will be restarted if it exceeds the amount of memory specified. human-friendly format : it can be “10M”, “100K”, “2G” and so on…
env object {“NODE_ENV”: “development”, “ID”: “42”} env variables which will appear in your app
env_ object {“NODE_ENV”: “production”, “ID”: “89”} inject when doing pm2 restart app.yml –env
source_map_support boolean true default to true, [enable/disable source map file]
instance_var string “NODE_APP_INSTANCE” see documentation

Log files

Field Type Example Description
log_date_format (string) “YYYY-MM-DD HH:mm Z” log date format (see log section)
error_file (string) error file path (default to $HOME/.pm2/logs/XXXerr.log)
out_file (string) output file path (default to $HOME/.pm2/logs/XXXout.log)
combine_logs boolean true if set to true, avoid to suffix
merge_logs boolean true alias to combine_logs
pid_file (string) pid file path (default to $HOME/.pm2/pid/app-pm_id.pid)

Control flow

Field Type Example Description
min_uptime (string) min uptime of the app to be considered started
listen_timeout number 8000 time in ms before forcing a reload if app not listening
kill_timeout number 1600 time in milliseconds before sending a final SIGKILL
wait_ready boolean false Instead of reload waiting for listen event, wait for process.send(‘ready’)
max_restarts number 10 number of consecutive unstable restarts (less than 1sec interval or custom time via min_uptime) before your app is considered errored and stop being restarted
restart_delay number 4000 time to wait before restarting a crashed app (in milliseconds). defaults to 0.
autorestart boolean false true by default. if false, PM2 will not restart your app if it crashes or ends peacefully
cron_restart string “1 0 * * *” a cron pattern to restart your app. Application must be running for cron feature to work
vizion boolean false true by default. if false, PM2 will start without vizion features (versioning control metadatas)
post_update list [“npm install”, “echo launching the app”] a list of commands which will be executed after you perform a Pull/Upgrade operation from Keymetrics dashboard
force boolean true defaults to false. if true, you can start the same script several times which is usually not allowed by PM2

混合app集成热更新

原因是因为之前做的都是纯 rn 项目,偶尔接入原生,所以 codepush 比较好集成.

有一次在想如果原本是原生的项目,后面只是引入 rn 作为一些基础模块,这样的更新要如何做,也就有了这篇文章(技术很早实现了,博客因为懒后面盆友需要,拖了现在才写,也是尴尬);

1. 前提工作

你目前的 iOS 项目已经是 ReactNative 混合 App;
这边我用我之前的来做,具体代码可以看这个链接(国内Coding)或者这个链接(国外github);

2. 了解一些 codepush 的原理

之前在 CSDN 写的 codepush 相关的博客

CodePush 热更新ReactNative之CodePush CLI操作

CodePush 热更新ReactNative之React Native Client SDK

可以看下了解,当然最好去官方 gayhub 去看文档比较好;

按照文档吧 codepush 的环境安装好👌;

3. 集成进入 App 项目里

  1. 安装 codepush 模块 npm install --save react-native-code-push@latest;
  2. 在安装完成后,可以执行命令自动导包进去 react-native link react-native-code-push, 当然也可以手动导包,自己看下官方文档;
    在自动导包时,会要求你添加 codepush 的 key, 可以跳过下面会说到怎么添加;
  3. 到此就可以看到 package.json 里面多了一个模块;
    目录变化
    目录变化

原生项目文件变化,添加了 CodePush 工程,还有一些静态库,至于 AppDelegate.m 里面的好像是会有,有点忘记了;
原生项目文件变化

4. 配置 codepush 的 key

  1. codepush 创建 app code-push app add MyApp-iOS 会从中得到一个 key ,复制这个 key ,下一步在 iOS 原生中会用到;
    key
  2. iOS中原生配置 key ,在 Info.plist 文件中,如下图;

5. 原生代码配置

  1. AppDelegate.m 文件中配置,为了一进入 App 就加载好了, codepush 环境,我个人认为的,没有去测试;
  2. 在每处用到混合的地方加入代码,这边我用到了两处,所以两个的 .m 文件中,我都加入类似的代码;

6. js 代码的配置

js 基本的配置就是这些,具体的有些配置,可以官方文档看下;

7. iOS 打 release 包

  1. 在 js 主目录下,执行命令 curl http://localhost:8081/index.ios.bundle -o main.jsbundle 会在目录下有个 main.jsbundle 的文件,这个需要拖到 iOS 原生目录下,每次打包重新生成,都需要替换进去;
  2. iOS 打包 ipa 包,只要把刚才的 main.jsbundle 拖进去,剩下的步骤和正常打包一样;

8. 打 codepush 更新包

在 js 的目录下,执行命令 code-push release-react youAppName ios, 最简单命令,直接推到Staging;

9. 到此基本结束,根据你设置的更新条件, App 就会自动更新了;

如何在现有的iOS项目中添加ReactNative混合开发

如果公司的项目之前是用原生, 现在想做混合开发并且选择ReactNative, 这篇会是一个基础的环境配置;

1. 开发环境准备

首先, 至少你已经搭建了 React Native开发环境在iOS平台上所需的一切依赖软件(比如npm)。

其次, CocoaPods 包管理工具, 基本做iOS开发都有装, 如果没有, 那就百度一下😂;

2. 安装依赖包

React Native的植入过程同时需要React和React Native两个node依赖包。

在你的原有的iOS目录的上一级目录创建一个包管理package.json文件;

对于一个典型的React Native项目来说,一般package.json和index.ios.js等文件会放在项目的根目录下。而iOS相关的原生代码会放在一个名为ios/的子目录中,这里也同时放着你的Xcode项目文件(.xcodeproj)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// package.json 文件内容
{
"name": "NumberTileGame",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"react": "15.4.1",
"react-native": "0.39.2"
}
}

// 通过npm info react和npm info react-native 来查看当前的最新版本

npm install // 在 package.json 的当前目录下开启终端执行这段代码, 这些模块就会安装到 node_modules/ 下;

3. React Native框架嵌入iOS

Subspecs

在你开始把React Native植入到你的应用中之前,首先要决定具体整合的是React Native框架中的哪些部分。而这就是subspec要做的工作。在创建Podfile文件的时候,需要指定具体安装哪些React Native的依赖库。所指定的每一个库就称为一个subspec。

可用的subspec都列在node_modules/react-native/React.podspec中,基本都是按其功能命名的。一般来说你首先需要添加Core,这一subspec包含了必须的AppRegistry、StyleSheet、View以及其他的一些React Native核心库。如果你想使用React Native的Text库(即组件),那就需要添加RCTText的subspec。同理,Image需要加入RCTImage,等等。

Podfile

在 CocoaPods 的 Podfile 中指定我们所需要使用的组件。如果原生没有用过 CocoaPods 管理;

//在iOS原生代码所在的目录中(也就是.xcodeproj文件所在的目录)执行:
pod init

Podfile 会创建在执行命令的目录中。你需要调整其内容以满足你的植入需求。调整后的Podfile的内容看起来类似下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# target的名字一般与你的项目名字相同
target 'NumberTileGame' do

# 'node_modules'目录一般位于根目录中
# 但是如果你的结构不同,那你就要根据实际路径修改下面的`:path`
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'RCTText',
'RCTNetwork',
'RCTWebSocket', # 这个模块是用于调试功能的
# 在这里继续添加你所需要的模块
]

end

Pod安装

创建好了Podfile后,就可以开始安装React Native的pod包了。

pod install

4. 代码集成

原生代码集成

在要混合开发的页面, 加入如下代码

1
2
3
4
5
6
7
8
9
10
11
12
// RNViewController 页面
- (void)viewDidLoad {
[super viewDidLoad];

NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL : jsCodeLocation
moduleName : @"HybridApp"
initialProperties : @{@"page" : @"RN1"} // 传入参数,用于定义那个页面或者一些数据传输
launchOptions : nil];
self.view = rootView;
}

ReactNative代码集成

index.ios.js js 代码的入口

1
2
3
4
5
'use strict';
import {AppRegistry} from 'react-native';
import App from './app';
AppRegistry.registerComponent('HybridApp', () => App);
// 注册模块

app.js 在这边做页面判断,当然你也可以根据自己的需求去做调整

1
2
3
4
5
6
7
8
9
10
11
12
13
'use strict';

import React from 'react';
import RN1 from './ReactNative1';
import RN2 from './ReactNative2';

export default class App extends React.Component {
render() {
return (
this.props['page'] == 'RN1' ? <RN1 />:<RN2 />
);
}
}

ReactNative1.js 页面1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'use strict';

import React from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
export default class ReactNative1 extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>ReactNative1</Text>
<View style={{height: 100, width: 100, backgroundColor: 'blue'}} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});

ReactNative2.js 页面2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
'use strict';
import React from 'react';
import {
StyleSheet,
Text,
View
} from 'react-native';
export default class ReactNative1 extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>ReactNative2</Text>
<View style={{height: 100, width: 100, backgroundColor: 'red'}} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF',
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10,
}
});

>>项目gayhub地址<<
效果展示

因为微软开源的这个做的还不错,所以拿来用了

1. CodePush CLI安装

  • 首先要安装Node.js
  • CodePush CLI安装 : npm install -g code-push-cli

2. Account 账号管理

  • 注册code-push register
    codePush注册页面
    一般可以使用github登录(建议),也可以注册微软的账号!
  • 退出账号后可以用code-push link,进入页面
  • 登录 code-push login

    条状页面,通过上面的那些图登录
    选择登录方式

    登录的key

    输入key

  • 当前登录账号 code-push whoami
  • 退出当前登录 code-push logout
  • 显示在那些电脑上面登录过账号 code-push session ls
  • 移除在某台电脑的登录 code-push session rm <machineName>

  • 获取access-key不通过浏览器 code-push access-key add "VSTS Integration"
  • 通过上面的key登录 code-push login --accessKey <accessKey>
  • 设置key到期时间 code-push access-key patch <accessKeyName> --name "new name" --ttl 10d
  • 登录HTTPS_PROXY or HTTP_PROXY安全的一些东西code-push login --noProxy code-push login --proxy https://foo.com:3454

3. App 管理

  • 新建推送热更新的App code-push app add <appName>

    建议是iOS和安卓版本分开创建
    code-push app add MyApp-Android
    code-push app add MyApp-iOS

  • 对App进行改名字 code-push app rename <appName> <newAppName>

  • 移除App code-push app rm <appName>

  • 列出账号的所有App code-push app ls

  • App 增加参与的管理者(一般少用) code-push collaborator add <appName> <collaboratorEmail>

  • 移除参与的管理者 code-push collaborator rm <appName> <collaboratorEmail>

  • 列出所有的参与者 code-push collaborator ls <appName>

  • 把自己的这个App管理权限转移给其他人 code-push app transfer <appName> <newOwnerEmail>

4. 开发环境管理

  • 增加开发环境 code-push deployment add <appName> <deploymentName>
  • 移除 code-push deployment rm <appName> <deploymentName>
  • 换名字 code-push deployment rename <appName> <deploymentName> <newDeploymentName>
  • 列出所有的开发环境 code-push deployment ls <appName>
  • 列出所有的开发环境和对应access-key code-push deployment ls <appName> --displayKeys 或者 -k
    环境

    Active 当前表示激活比例
    Total 总共多少
    Pending 处于未升级和不确定因素
    Rollbacks 回滚的数
    Rollout
    Disabled

5. 更新版本管理

  • 最简单的方法 code-push release-react MyApp ios code-push release-react MyApp android
  • code-push release-react hxlivei ios -d “PrePush” –des “停车场”

    code-push release-react
    [–bundleName ]
    [–deploymentName ]
    [–description ]
    [–development ]
    [–disabled ]
    [–entryFile ]
    [–mandatory]
    [–plistFile ]
    [–plistFilePrefix ]
    [–sourcemapOutput ]
    [–targetBinaryVersion ]
    [–rollout ]

6. 其他

  • 清除更新记录 code-push deployment clear <appName> <deploymentName>
    清除历史