知识点:
1.封装一个自己的日志,代替原生的console
2.封装一个自己的请求库,代替原生的fetch
3.自适应方法,兼容各种手机屏幕
4.封装一个本地存储
5.集成toast弹出提示
6.让iOS支持http地址
7.安卓需要证书才能编译
在正式开始之前,我们先封装几个要用到的库。
自定义本地日志
自定义日志的一个好处就是省的每次都要手动注释console。而且还可以同时将日志存在本地,或者发到日志服务器。一个方法就一举多得了。
在src目录下新建一个utils文件夹。我们封装一个日志输出类。开发模式下使用console.log
命令。正式情况下记录在变量中,方便在手机上查看日志。
新建一个log.js文件。路径为根目录/src/utils/log.js
。
新建一个数组变量logs
,用来临时存放日志信息。
将日志分成信息、警告和错误3种,分别给出3个可调用的方法。同时给第一个参数加一个好看的颜色。
在index中引入日志组件,写几个方法看看调用的结果。
这里稍微定义一下日志的要求。参数0,字符串。参数1,对象。参数2,字符串。
自定义请求
RN默认提供了fetch方法去请求远程数据。我们再封装一次,将这个方法将会针对现有的项目做封装,在使用请求的时候能够更适合、更方便。这里使用header保存了一些临时的变量,算是一个小小的全局缓存吧。
创建request.js文件,目录:根目录/src/utils/request.js
。
将请求header里的信息单独出来,每次请求都需要带上这个共享header数据。
创建一个Request类,并将这个类对外公开。这里讲请求初始化一次,以后用到别的请求的时候也可以单独实例化一次。1
2
3
4
5
6/**
* 请求库
*/
class Request {}
export default new Request();
每次请求都将header中的内容带入请求中,单独检测httpcode和后端返回的code值。这里可以直接做权限检测,在需要的时候跳转到登录页。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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88/**
* 请求库
*/
class Request {
/**
* 检测返回状态码
* @param {*} status
* @param {*} res
*/
async _checkStatus(status, res, url) {
if (status !== 200) {
logWarm('请求失败参数', await res.text(), url, headers);
throw new Error('网络连接失败,请检查网络');
}
}
/**
* 检查后端返回的状态码
* @param {*} status
*/
_checkAppStatus(json, url) {
if (json.status != 0) {
logWarm('返回状态报错', json, url);
throw new Error(`${json.errorMsg}`);
}
}
/**
* 内部实现网络请求
* @param {*} url
* @param {*} options
*/
async _request(url, options, type) {
url = url.indexOf('http') == 0 ? url : url.indexOf('/api') == 0 ? domain + url : baseUrl + url;
let res = await fetch(url, options);
this._checkStatus(res.status, res, url)
if (type === 'json') return await this._jsonFactory(res, url, options)
return await this._jsonFactory(res, url, options)
}
/**
* 处理json数据
* @param {*} res
* @param {*} url
*/
async _jsonFactory(res, url, options) {
let json;
let txt = '';
try {
txt = await res.text();
} catch (e) {
log('未拿到返回字符串', { url: url, txt: txt });
throw new Error('数据格式错误');
}
try {
json = JSON.parse(txt);
} catch (e) {
logErr('返回数据格式错误', { url: url, txt: txt });
throw new Error('数据格式错误');
}
this._checkAppStatus(json, url)
log("请求返回", json, url, options);
return json.data;
}
/**
* get请求
* @param {*} url
*/
async get(url, data) {
if (data) data = urlEncoded(data);
if (url.indexOf('?') < 0 && data) url += '?' + data;
return this._request(url, {
method: 'GET',
headers: headers,
timeout: 10000
}, 'json')
}
/**
* post请求
* @param {*} url
* @param {*} data
*/
async post(url, data) {
return this._request(url, {
method: 'POST',
headers: Object.assign(headers, { 'Content-Type': 'application/x-www-form-urlencoded' }),
timeout: 10000,
body: urlEncoded(data)
}, 'json')
}
}
调用一次远程端口并查看日志输出。这里调用的也是案例中要使用到的获取banner的接口。这个接口不需要用户权限,后面还会遇到需要用户权限的接口。
自适应方法
这里推荐一种自适应的方法。同时也是前端在开发移动端页面的时候常用的方法。将手机屏幕宽度默认为750像素,然后将所有的宽高按照这个比例去缩放。这要求设计出的设计稿也要宽度是750。
在utils下新建一个px.js
文件。按照出入的大小根据当前屏幕的宽度获取到缩放的比例并返回结果。
在首页引入px方法,查看使用px之后的效果。
可以看到使用px将500像素缩放之后的效果和最开始设置的纯数字200效果是一致的。这里使用的是ios模拟器,真实的屏幕宽是375,按照750宽去算的话会把传入的参数统统除以2。
封装本地存储
RN提供的AsyncStorage可以根据key存储相应的字符串。我们这里改进一下,让它可以存储所有类型的字段。利用的是将传入的参数改造成对象,然后使用JSON的方法将对象转化成一个可以存储的字符串。
在utils下新建一个Storage.js
。
将传入的对象转化为字符串并存入AsyncStorage。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 ;
import { AsyncStorage } from 'react-native';
/**
* 获取存储的数据
* @param {*} key
*/
exports.getItem = async (key) => {
let item = await AsyncStorage.getItem(key);
if (!item) {
return null;
}
return JSON.parse(item).v || null;
}
/**
* 存入数据
* @param {*} key
* @param {*} value
*/
exports.setItem = (key, value) => AsyncStorage.setItem(key, JSON.stringify({
v: value
}));
/**
* 删除已经存在的数据
* @param {*} key
*/
exports.removeItem = (key) => AsyncStorage.removeItem(key);
/**
* 清除所有
*/
exports.clear = () => AsyncStorage.clear();
/**
* 获取所有的key
*/
exports.getAllKeys = () => AsyncStorage.getAllKeys();
在首页使用setItem存入数据,然后第二次进入页面再使用getItem获取数据。
这里用到了componentDidMount这个方法。这个方法是在组件生命周期中的初始化完成之后执行的。
添加弹出toast
之前公司使用的是自己开发的提示方法,这个方法需要改变原生代码,非常的不方便。这里推荐使用第三方的开源组件react-native-root-toast
。只需要安装一下就好了。
执行命令,安装toast。npm i --save react-native-root-toast
。
在utils目录下新建toast.js文件。添加toast的默认方法并填入默认参数。这里设置显示时间为1000毫秒,背景颜色是一个半透明的黑色。这里也是为了方便调用,如果需要多种效果的就定义多个吧。
在首页引入toast并看看实际的效果。
让iOS支持http协议
苹果之前推荐使用https协议,现在默认是不支持http的。如果需要支持http需要单独设置。案例中的项目也用到了http,所以需要修改info.plist文件,让iOS可以访问http的地址。
使用xcode选择打开其他项目。
打开项目下的iOS文件夹,选择项目文件并打开。
选择info.plist文件,再右边选择第一行并点击+号添加一项。
选择App Transport Security Setting这一项,会弹出提示。点击确定即可自动刷新。
在上面添加的新配置中添加一个新的配置Allow Arbitrary Loads,同时设置为YES。
改完配置还需要编译一次。点击左上角的三角形或者菜单中product下的build选项。
这里我使用的是xcode修改配置文件,如果你发现配置文件没有变化,也可以自己改info.plist文件的内容。
编译安卓客户端
使用android studio打开根项目下的android目录。打开build.gradle文件。这个就是项目的gradle配置文件,通常使用这个文件对整个项目进行描述。
经过一定时间的等待,IDE就会初始化整个项目。如果有一些需要下载的文件也会在这个时间通知下载。
点击菜单build/gennerate signed apk
。这个就是编译一个可以安装在安卓手机上的安装包。也可以通过点击make project
来看看项目是否可以编译通过。
点击next,IDE会提示需要选择一个证书。这里可以选择一个已有的并输入密码,也可以通过点击create new
来创建一个。后面一直点击next就可以了,IDE会在生成apk之后弹出通知。
选择创建一个新的证书。根据提示填入相应的内容,之后点击ok即可生成。记得选择remember password,下次直接填入密码。
经过一整机器躁动之后,IDE弹出编译结果。点击蓝色字可以快速打开apk的地址。
将apk文件发送到手机上安装即可。一个你自己开发的app就安装好了。
这里要注意,在打包之前要把RN打包生成的bundle文件放入android文件下的assets目录中。否则安卓会因为找不到启动文件而报错。