jpush-expo-config-plugin

一个极光推送的 Expo 自动配置插件, 免去配置原生项目的繁琐步骤

此软件包不能在 “Expo Go” 应用程序中使用

1. 安装

1
2
3
npm install jpush-expo-config-plugin --save
或者
yarn add jpush-expo-config-plugin

注意: 如果项目里没有 jpush-react-native、jcore-react-native, 需要安装

1
2
3
npm install jpush-react-native jcore-react-native --save
或者
yarn add jpush-react-native jcore-react-native

2. 配置

安装此 npm 包后, 请将 配置插件 添加到 app.json 或 app.config.js 的 插件数组 :

app.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"expo": {
"plugins": [
[
"jpush-expo-config-plugin",
{
"appKey": "你的极光推送AppKey",
"channel": "你的极光推送Channel"
}
]
]
}
}

接下来, 按照 “添加自定义 Native 代码” 指南中的描述重新构建应用程序

1
expo prebuild

expo 没办法使用 react-native-amap3d (尝试过, 会报错 module null), 需要 expo eject 变为 react-native 项目, 进行 react-native link (从 v2.0.0 开始支持 RN 的 autolinking,不再需要手动配置。), expo eject 会导致 expo start 等功能不能用.
萌新前端, 请多多包涵!~OWO

初始化 Expo 项目

如果没有安装 expo/cli 先 npm i -g expo/cliyarn global add expo/cli 进行安装

1
2
3
4
5
$ expo init

What would you like to name your app? (你想为你的应用命名什么)

Choose a template (选择模板)

Eject Expo 项目

1
2
3
4
5
6
7
$ npm run eject
or
$ yarn eject

What would you like your Android package name to be? (您希望 Android 包名是什么?)

What would you like your iOS bundle identifier to be? (您希望 iOS bundle identifier 是什么?)

初始化项目环境

如果直接使用 npm run androidyarn android 会报错 error Failed to install the app. Make sure you have the Android development environment set up (错误:无法安装应用程序。确保您已经设置了 Android 开发环境)

需要使用 Android Studio 先打开此项目下的 android 文件夹, 它会自动帮你设置环境!

启动项目

1
2
3
$ npm run android
or
$ yarn android

我所在的 Expo 版本有个坑, 如果直接使用 npm run androidyarn android 会报错 (如果启动成功, 直接略过此处)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xxx/my-app/android/app/src/main/java/com/runomeow/myapp/MainActivity.java:19: 错误: 对于show(MainActivity,SplashScreenImageResizeMode,boolean), 找不到合适的方法
SplashScreen.show(this, SplashScreenImageResizeMode.CONTAIN, false);
^
方法 SplashScreen.show(Activity,SplashScreenViewProvider,Class<? extends ViewGroup>,boolean,Function0<Unit>,Function1<? super String,Unit>)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenViewProvider,Class<? extends ViewGroup>,boolean,Function0<Unit>)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenViewProvider,Class<? extends ViewGroup>,boolean)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenImageResizeMode,Class<? extends ViewGroup>,boolean,SplashScreenViewProvider,Function0<Unit>,Function1<? super String,Unit>)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenImageResizeMode,Class<? extends ViewGroup>,boolean,SplashScreenViewProvider,Function0<Unit>)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenImageResizeMode,Class<? extends ViewGroup>,boolean,SplashScreenViewProvider)不适用
(实际参数列表和形式参数列表长度不同)
方法 SplashScreen.show(Activity,SplashScreenImageResizeMode,Class<? extends ViewGroup>,boolean)不适用
(实际参数列表和形式参数列表长度不同)

issues#9047

结合 issues 修改 /android/app/src/main/java/com/runomeow/myapp/MainActivity.java:19 就可以了

1
2
3
4
5
找到
SplashScreen.show(this, SplashScreenImageResizeMode.CONTAIN, false);

改为
SplashScreen.show(this, SplashScreenImageResizeMode.CONTAIN, ReactRootView.class, false);

使用 react-native-amap3d

注意, 一定要设置 <MapView /> 宽高才能显示. react-native-amap3d 不支持 x86 平台, 模拟器运行会闪退, 真机运行正常!

1
2
3
$ npm install react-native-amap3d
or
$ yarn add react-native-amap3d

修改 App.tsx

1
2
3
4
5
6
7
8
9
10
11
12
import { MapView } from 'react-native-amap3d';

<MapView
center={{
latitude: 3,
longitude: 106,
}}
style={{
width: 233,
height: 233,
}}
/>;

一直用别人的有点没意思 QAQ
摸鱼自己写一个试试
渣渣代码慎入!!!

演示图片

JavaScript

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
const list = document.getElementById('list'); // 获取元素
list.addEventListener('click', () => scrollAnimate(list, 200, 1000, 120)); // 绑定事件

// scrollElement 列表元素
// newScrollTop 移动到什么位置
// direction 动画时间
// fps 帧率
function scrollAnimate(scrollElement, newScrollTop, direction, fps = 60) {
const oldScrollTop = scrollElement.scrollTop; // 原来的位置
const diffScrollTop = newScrollTop - oldScrollTop;// 相差多少
const tickTime = 1000 / fps; // 根据FPS计算每一帧延迟
const num = 1 - 60 / fps / (direction * 0.01); // 根据FPS计算每一帧移动百分之多少
let rate = num; // 当前百分比(默认移动一帧)

const timer = setInterval(() => {
const nowScrollTop = oldScrollTop + diffScrollTop * (1 - rate); // 原来的位置 + 差多少 * 百分比 (0 + 200 * (1 - 0.95))
if (Math.abs(newScrollTop - nowScrollTop) > 1) {
// 如果位置绝对值大于1px, 移动滚动条
scrollElement.scrollTo(0, nowScrollTop);
} else {
// 清除时钟, 直接设为需要移动到的位置
clearInterval(timer);
scrollElement.scrollTo(0, newScrollTop);
}
rate *= num; // 计算百分比(0.95 * 0.95 不断减少)
}, tickTime);
}

HTML

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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Runo</title>
<link rel="stylesheet" href="main.css" />
</head>
<body>
<div id="list">
<div class="list-item">
<div class="list-title">
<div class="list-left">
<span>喵了个咪喵了个咪</span>
</div>
<div class="list-right">
<span>2020-7-24 10:51:49</span>
</div>
</div>
<div class="list-content">
<span>喵呜喵呜喵呜</span>
</div>
</div>
<div class="list-item">
<div class="list-title">
<div class="list-left">
<span>喵了个咪喵了个咪</span>
</div>
<div class="list-right">
<span>2020-7-24 10:51:49</span>
</div>
</div>
<div class="list-content">
<span>喵呜喵呜喵呜</span>
</div>
</div>
<div class="list-item">
<div class="list-title">
<div class="list-left">
<span>喵了个咪喵了个咪</span>
</div>
<div class="list-right">
<span>2020-7-24 10:51:49</span>
</div>
</div>
<div class="list-content">
<span>喵呜喵呜喵呜</span>
</div>
</div>
<div class="list-item">
<div class="list-title">
<div class="list-left">
<span>喵了个咪喵了个咪</span>
</div>
<div class="list-right">
<span>2020-7-24 10:51:49</span>
</div>
</div>
<div class="list-content">
<span>喵呜喵呜喵呜</span>
</div>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>

CSS

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
body {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}

#list {
width: 750px;
height: 750px;
overflow-y: auto;

background-color: #f0f0f0;
border-radius: 10px;
}
.list-item {
position: sticky;
top: 10px;
margin: 10px;
padding: 10px;
display: flex;
align-items: center;
flex-direction: column;
height: 100px;
overflow: hidden;
box-sizing: border-box;

background-color: white;
border: 1px solid black;
border-radius: 10px;
}
.list-item:last-of-type {
margin-bottom: 640px;
}
.list-title, .list-content {
width: 100%;
}
.list-title {
display: flex;
align-items: center;
justify-content: space-between;

}
.list-left {

}
.list-right {

}
.list-content {
overflow: hidden;
}

每次更新文章都要生成一次就太麻烦啦!
于是利用 GitHub 的 Webhooks 做一个自动化部署
大概说一下搭建的经过~

Runo+ Blog
GitHub Webhooks

安装以下几个包

  • express 服务端
  • node-cmd 用于执行命令
  • crypto 校验 sha1(可选)
  • dotenv 加载.env(可选)
1
npm install express node-cmd crypto dotenv --save

在 hexo 项目下新建一个 webhooks.js

hmmm 萌新代码写的不好 见谅

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
const express = require('express');
const app = express();
const nodeCmd = require('node-cmd');
const crypto = require('crypto');
require('dotenv').config();

// JSON支持
app.use(express.json());

// 监听POST请求
app.post('/apis/update', (req, res) => {
// github通过秘钥+请求体算出来的sha1(如果不需要校验的话 下面的校验过程可不要)
const sign = req.headers['x-hub-signature'];
const sha1 =
'sha1=' +
crypto
.createHmac('sha1', process.env.GITHUB_WEBHOOKS_SECRET)
.update(JSON.stringify(req.body))
.digest()
.toString('hex');
if (!sign || sign !== sha1) return res.send('secret error');
// 使用 node-cmd 执行 git pull 拉取仓库
nodeCmd.get('git pull', (err, data) => {
if (!err) {
console.log(data);
// 使用 node-cmd 执行 npx hexo generate 生成页面
nodeCmd.get('npx hexo generate', (err, data) => {
if (err) console.error(err);
else console.log(data);
});
} else console.error(err);
});
res.send('success');
});

// 监听端口
app.listen(process.env.GITHUB_WEBHOOKS_PORT, () =>
console.log('listening ' + process.env.GITHUB_WEBHOOKS_PORT)
);

进行服务器的部署

  1. 将代码提交后, 在服务器 git clone

  2. 执行 npm run build 会在 public 文件夹生成静态网页, 再使用 nginx 等web服务器, 把域名指向 public 文件夹

  3. 使用 pm2 start 启动 webhooks.js, 服务端就算是部署好啦!

为仓库添加 Webhook

  1. 打开 GitHub 仓库

  2. 依次点击 Setting → Webhooks → Add webhook

设置 Webhook

  1. Payload URL: 需要响应的地址 (例如 https://runo.plus/xxx)

  2. Content type: 请求的内容类型 (选择 application/json)

  3. Secret: 秘钥 (需要与服务器上的一样! GITHUB_WEBHOOKS_SECRET, 如果不需要校验则省略)

  4. 选择 Just the push event. (仓库接到推送后触发)

  5. 勾选 Active

  6. 点击 Add webhook 完成添加

提交一次仓库试试效果owo~