豪翔天下

Change My World by Program

0%

应该和很多人一样,拿起这本书的时候就想看看这本魔法书里到底有什么黑魔法,会不会有很多奇淫技巧,很多强大的收纳工具。当然,最后证明,这里面什么都没有。它反而像一本心灵治愈类的书籍,从精神的高度来教我们整理房间、整理人生。当然,最后的最后,依然没有治疗我的拖延症,不过倒是让我对自己所拥有的物品们产生了一种敬畏感。

去年年底买了人生的第一套房,住进来已经一个多月了。刚帮进来的时候,父母帮我收拾了一大部分的东西。基本上只有客厅的一些不知道怎么归类的杂物没有整理以外,其他的东西都已经各有所处了。秉着每天收拾一点点的原则,一个多月以来,终于使得每个房间都如最开始的时候那样杂乱了。衣服分散在衣柜、床上、沙发,洗衣机上面;电视柜下面交换机、无线路由器、电视盒子、nas主机,各种线缆杂乱纷争;原本不知道怎么分类的杂物也随着不停的网购变得越来越多。就这样的状态,我都已经不害臊地请了好几次朋友们来我新家里做客了。

看了此书,最大的感悟就是终于明白了那么一句话:一屋不扫,何以扫天下。不是什么特别大的道理,也不是叫你要干出一番大事业,只是,当你不知道如何整理自己最亲近的这些东西的时候,可能你还缺少了一份对生活应有的积极态度。当你能学着扔掉大多数你买错了并且你心里也清楚确实买错了的东西的时候,就不会被太多的欲望占据了你的生活,你的生活本来就应该简简单单的。我觉得在今后的生活中,至少我还需要作如下的改变:

  • 我知道自己总是舍不得丢掉以前那些能带给我回忆但是却真心没用的东西,所以,我打算还是扔掉他们,但是在每次扔掉之前,拍一张照片,保留一份电子的照片和打印出来的照片就可以了。
  • 尽量一次整理完,而不是每次只整理一点点,每次只整理一点点永远整理不完。
  • 少依赖收纳神器,家里的收纳已经够用了。
语录

如果一个人不是发自内心地想要做一件事,那么,他是无法改变自己的人生的

其实每样物品各有各的作用,并非所有衣服都是因为要被完全穿坏才来到你的身边

厨房好用与否,关键不在于收纳,而是清理的容易成粗。

我们的目标是争取在理想的房间里过上理想的生活,而穿着没有新动感的家居服待在房间里实在太可惜了。

所谓整理,就是整理每一件物品的“过去”。

不管多么凌乱的房间,整理都只是一种物理性的作业。东西毕竟不是无穷无尽的,只要能留下让自己心动的东西,给它们固定位置,整理工作就一定会结束。

真正的必需品肯定是能让自己幸福的东西,所以,应该积极地把必需品当做“心动物品”来对待。

这个忙碌的五月,继续拜读了王小波的书,《一只特立独行的猪》。先说一下看书的心境。这个月完成了人生的一件大事,搬进了新家,自己的房子,自己的家。从此以后,在城市里有了自己的一个方格子,有了自己的一片小天地了,开始了自己梦想中的生活。每天七点起床,用kindle看半个多小时的书,然后起床洗漱,再然后做早餐,然后收拾一下,出门上班。生活中有些事情每天我们都得重复,但是谁又能说就一定很无聊呢。每天看不同类型的书,每天做不同口味的菜,每天有没有一天的惊喜和意外,多么有趣的生活。

王小波是一个有趣的人,“活在世上,无非想要明白些道理,遇见些有趣的事”,王小波人如此,做事如此,写书也如此。从小到大,看够了语文课本上那群大师的严肃文学作品,现在开始迷上王小波这种类型的作品了。当然,绝不仅仅是有趣,我们和他生活的时代完全不同,要谈感同身受的有趣,那肯定是不对的,有趣的是,他的作品确实能让我们感到有趣。没有对现实的阿谀奉承,没有随大流,而是真正的以一个平凡人的角度,看待问题,看待这个世界,我觉得这是文学永恒不变的主题,源于生活,高于生活。

有时候我想问问王小波,比尔盖茨的紧身衣现在还没发明出来,但肯定在研发中,知道AlphaGo吗,你对人工智能怎么看?不过今天的文学可能和你那个时候相比变样了,网络文学的兴起,传统文学的没落,当然也出想过许多红极一时的书,但是已经很久没有出现过那种能够流传千古的著作了,你要不再来挥墨作文?虽然不是每个人都读过你的书,但相比于以前,现在这个年代可能是离你梦想最近的时代。人人可以追求自由,人人都是特立独行,人人都可以无视生活的设置,肆意地追逐心中所想。你说,这是文明的进步还是退化呢?

至于我的生活能不能一直有趣下去呢?还是自己来书写答案吧!

语录:

井底之蛙也拥有一片天空

只按名声来理解文学,就会不知道什么是坏,什么是好。

同性恋研究给我们以这样的启示:倘若生活中存在着完全不能解释的事,那很可能是因为有我们所不知道的事实,而不知道的原因却是我们并不真正想知道。比如我们以前不知道同性恋的存在,是因为我们是异性恋;我们不知道农民为什么非生很多孩子不可,是因为我们是城里人。

这世界上有很多书都是这样的:内容无可挑剔,只是很没有意思。

假如你想听听电脑,我可以说,现在在中关村花二百五十块钱可以买到八兆内存条,便宜死了……

我原是学理科的,学理科的不承认有牢不可破的囚笼,更不信有摆不脱的噩梦;人生唯一的不幸就是自己的无能。

我总觉的文学的使命就是制止整个社会变得无趣……

人们知道得越多,明辨是非就越困难

学生是穷人中最趾高气扬的一种:虽然穷,但前程远大。

我总觉得,大多数人在受到重视之后,行为就会好。

我时常回到童年,用一片童心来思考问题,很多烦恼的问题就变得易解。

基础概念

**特别注意: **

  • React-Native是基于React实现的,更多语法可以参考React 开发手册
  • 如果是自己开发新产品,那么希望每次都把各个基础组件升级到最新稳定版。

React Native开发的优点

  • 拥有系统级别的通知或提醒
  • 可以访问本地通讯录、相册等资源
  • 可以针对不同的平台提供不同的体验

React Native采用的是ES2015(即ES6)的语法标准,模板上使用了自己的JSX语法(在代码中嵌入结构标记)。

环境搭建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 初始化项目
npm uninstall -g react-native-cli # 官方说不要用这个来初始化了,并且得卸载了,否则可能出现奇怪的问题
npx react-native init testProject --verbose # 新建项目目录,并初始化项目。命令会执行很久,且--verbose像没用似的,像卡死了一样
npx react-native init testProject --version 0.68.2 --verbose # 创建指定版本的项目
npx react-native init testProject --template react-native-template-typescript --verbose # 创建一个typescript的项目
npx react-native init testProject --template "react-native-template-typescript@6.10.*" --verbose # 创建一个typescript的项目,指定版本

## 运行项目
cd testProject
npx react-native start
npx pod-install
npx react-native run-ios # 第一次启动会很慢。等模拟器运行起来后可以直接Cmd+R刷新应用,Cmd+D打开调试菜单
npx react-native run-ios --simulator='iPhone 13 Pro Max' # 指定云行的模拟器的名称
npx react-native run-android # 安卓开发最好安装上android studio,这不仅会帮你安装java、jdk,而且还能直接管理安卓模拟器,把android studio配置好了以后,android的开发环境也好了

npm install --save react-native@X.Y # 直接指定版本号的更新升级,手动升级更爽。我不喜欢用react-native-git-upgrade来升级,需要注意的是,升级以后一定要顺便升级一下命令行工具react-native-cli,否则会可能会出现不预期的错误

prop&&state

两者可以说是大同小异,在大多数情况下,两者没什么很大的差别。两者的改变的时候,渲染的地方都会重新渲染。

prop: 一个组件的设置参数,可以理解为初始化参数或者对象的静态变量,并且可以在父组件中设置,在子组件中不可改变,但是可以一直往下传递至子子孙孙。

state: 更像是对象的一些变量,并且确实是经常改变的,只是父子之间不能传递。

1
2
3
4
// 动态设置某个状态值
this.setState({
results: value,
});

布局

不用css,但是类似css。所有的组件都有style属性。样式名是将默认的css的命名更改为了驼峰命名。一般使用StyleSheet.create在组件外面集中定义组件的样式。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 指定固定的高度和宽度用width和height,React Native中的尺寸都是无单位的。
<View style={{width: 50, height: '50%', backgroundColor: 'powderblue'}} />

// 弹性的高度和宽度用flex。flex为1的时候表示撑满所有的剩余空间,如果多个并列子组件一起使用,则他们会平分空间,并且值越大所占比例就越大。例如
<View style={{flex: 2, backgroundColor: 'skyblue'}} />

<View style={[styles.css1, styles.css2]} /> // 包含多个样式

// 这样还能直接看出来层级关系。例如<Text style={styles.red}>test</Text>
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});

Flexbox布局

规定某个组件的子元素的布局。flex的值就类似于栅栏布局中的row宽度,一个2一个1,那么画面总共可以分成三份这种,如果直接flex:1,那么就表示直接占据整个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 父视图属性
<View style={{
flex: 1,
flexDirection: 'row', // 规定布局方向,默认是column垂直方向布局,row表示水平方向布局
flexWrap:'wrap', // 默认为nowrap,表示子元素是否允许多行排列
justifyContent: 'flex-start', // 规定子元素沿着主轴的排列方式。可选项有flex-start、center、flex-end、space-around以及space-between
alignItems: 'stretch', //规定子元素沿着次轴(与主元素垂直的轴)的排列方式。可选项有flex-start、center、flex-end、stretch
}}>

// 子视图属性
<View style={{
alignSelf: 'auto', // 定义了flex容器内被选中项目的对齐方式可选auto, flex-start, flex-end, center, stretch
}}>

// flexGrow与flex有些类似,但是flex会使子元素的空间大小限定在父元素空间范围内,而flexGrow会使子元素起码维持其本身大小,再根据父元素是否有剩余空间进行空间分配。

居中问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 图标悬浮与图片的正中间,两者均居中对齐
<View style={{
justifyContent: 'center',
alignItems: 'center',
}}>
<Icon name="microphone" size={70} style={{
position: 'absolute',
zIndex: 1,
justifyContent: 'center',
alignItems: 'center'
}}/>
<Image source={require('../img/test.png')} style={{
width: 250,
height: 250,
alignItems: 'center',
justifyContent:'center',
}}
/>
</View>

定位问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 获取屏幕尺寸
import Dimensions from 'Dimensions';
Dimensions.get('window');

// 获取元素的位置: https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element
class MyComponent extends React.Component {
render() {
return <View ref={view => { this.myComponent = view; }} />
}
componentDidMount() {
// Print component dimensions to console
this.myComponent.measure( (fx, fy, width, height, px, py) => {
console.log('Component width is: ' + width)
console.log('Component height is: ' + height)
console.log('X offset to frame: ' + fx)
console.log('Y offset to frame: ' + fy)
console.log('X offset to page: ' + px)
console.log('Y offset to page: ' + py)
})
}
}

组件

Animated动画

第三方库里面那些酷炫的效果均是通过动画来实现的

1
2
3
4
5
6
7
8
9
10
11
12
const top = useRef(new Animated.Value(100)).current;	// 将一个属性变为可以执行动画的属性

<Animated.View>
<View style={{top}}></View>
</Animated.View>

top.setValue(1000); // 当改变值的时候用setValue来执行,就能让改变变得平滑
Animated.timing(top, { // 也可以自定义执行时间
toValue: 1000,
duration: 500, // 默认500
delay: 100, // 默认为0
}).start()

Button基础按钮

这个组件的样式是固定的,如果需要自定义,那么高级的按钮参考Touchable系列

1
2
3
4
<Button
onPress={() => this._func()}
title="按钮标题必填"
/>

Image

图片组件,如果我们在同一个目录里面同时包含a.png/a@2x.png,a@3x.png那么react native就能通过屏幕的分辨率自动选择不同尺寸的图片,并且在代码里面仅需要require(./img/check.png)就行了。

Navigation文档,Navigation已经单独成为一个模块,强烈建议不再使用老的导航器,导航器对比,在这里有其更详细的文档。在0.44版本移除了Navigator,该模块被移动到react-native-custom-components现在也仅用于兼容老版本。使用前得先安装npm install --save react-navigation。有如下三种类型的导航器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 看官网的意思就是要安装这些东西
npm install --save @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack

# ios需要执行
npx pod-install ios

# android需要再MainActivity中添加一个方法
import android.os.Bundle;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}

# 然后需要全局使用NavigationContainer包裹app,在app.js中
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
return (
<NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
);
}

StackNavigator

类似于普通的Navigator,体现在屏幕上方的导航栏

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
// StackNavigator用于创建多页面应用。其中每一个都是一个Component
import React from 'react';
import { View, Text } from 'react-native';
import { StackNavigator } from 'react-navigation';

class HomeScreen extends React.Component {
static navigationOptions = ({navigation}) => {return ()}; // 可以使用return的方法,这样可以在上面写一些逻辑
static navigationOptions = ({navigation}) => ({
title: '头部标题',
headerStyle: {
backgroundColor: '#ffffff', // 设置头部样式
},
headerTintColor: '#fff',
headerTitleStyle: { // 设置头部字体样式
fontWeight: 'bold'
},
headerRight: ( // 设置header bar的左右按钮
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#fff"
/>
),
// header头中直接进行页面跳转
headerRight: (<Button onPress={() => navigation.navigate('Setting')} title={'设置'} />),

});

componentWillMount() {} // render之前执行,并且永远只执行一次
render() {} // 渲染页面
componentDidMount() {} // 组件加载完成后执行,在render之后,已经有了DOM结构,不要把其他逻辑写在render,以防阻塞UI
componentWillReceiveProps() {} // 组件接收到一个新的prop时执行,这个方法在初始化render时不会被调用
shouldComponentUpdate() {} // 返回一个布尔值
componentWillUpdate() {} // 在组件接收到新的props或者state但还没有render时执行,初始化时不会执行
componentDidUpdate() {} // 组件更新完成后

render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
}

// 可以在App.js中声明所有的页面,默认放在第一个的为首页
export default StackNavigator({
Home: {
screen: HomeScreen,
},
});

// 组件之间跳转方式
this.props.navigation.push('Home'); // 跳转至新的场景,并且将场景入栈
this.props.navigation.navigate('Home', {param1: '...'}) // 将新路由推送到堆栈导航器,如果它不在堆栈中,那么跳转到该页面
this.props.navigation.goBack()

TabNavigator

类似于ios的TabBarController,屏幕下方的标签栏

DrawerNavigator

侧边弹出的抽屉效果

SafeAreaView

  • 使用该组件包裹可以自动实现异形屏的padding,也不用考虑android还是iOS
1
2
import { SafeAreaView } from 'react-native'	// 如果不工作,就使用下面的方式
import { SafeAreaView } from 'react-native-safe-area-context'

ScrollView滚动

可以在该组件下面添加任意组件,能轻松实现几个组件的共同滑动

1
2
3
4
5
6
7
8
9
const scrollViewRef = useRef<ScrollView>(null);

<ScrollView
ref={scrollViewRef}
scrollEnabled={false} // 禁用滚动
></ScrollView>

scrollViewRef.scrollToEnd() // 滑动到底部
scrollViewRef.scrollTo({x: 0, y: 100, animated: true}) // 滑动到指定位置

StatusBar状态栏

Text

  • 默认情况下,系统字体的大小会直接影响到APP里面的显示,我们需要防止这种情况,防止用户把字体调得太大,可以在app.tsx中全局设置:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import {Text, TextInput} from 'react-native';

    if (Text.defaultProps == null) {
    Text.defaultProps = {};
    Text.defaultProps.allowFontScaling = false;
    }
    if (TextInput.defaultProps == null) {
    TextInput.defaultProps = {};
    TextInput.defaultProps.allowFontScaling = false;
    }
1
2
3
4
<Text 
numberOfLines={2} // 最多显示几行,多的会被隐藏
ellipsizeMode={'tail'} // 多的显示省略号
/>

TextInput输入框

TextInput默认宽度与父节点相同。如果想要其在没有文字的时候也能占据宽度,可以设置flex:1并且父View也得设置flex:1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<TextInput
style={{
height: 40,
alignSelf: 'center', // 输入框文字居中
alignItem: 'center',
textAlign: 'center', // 这个才是输入框里面的文字居中
}}
autoCapitalize="none" // 禁用自动大写
textContentType="oneTimeCode" // 禁用自动填充,不显示键盘上面的password选项
returnKeyType="next" // 定义keyboard键盘右下角的字体或样式,可选next、done、go、join、search、send等
onSubmitEditing={() => {
nextInputRef.current.focus(); // 如果上面的是next,并不会自动跳转,而是需要使用下一个input的ref来进行focus操作
Keyboard.dismiss(); // 隐藏键盘
}}
onChangeText={(text) => this.setState({text})}
clearTextOnFocus={true}
keyboardType="numeric" // 仅允许数字
placeholder='请输入' // 默认是灰色的
value={this.state.text}
/>

Touchable*系列

  • hitSlop属性可以让可以点击的区域比实际的要大,非常适合在移动端的点击操作

  • 包括了触摸的相关事件(触摸、点击、长按、反馈等):

    • onPressIn: 触摸开始

    • onPressOut: 触摸离开

    • onPress: 单击事件

    • onLongPress: 长按事件

TouchableHighlight

触摸点击高亮效果。点击的时候,不透明度会降低,同时会看到变暗或者变量。只支持一个子节点,如果要多个子视图组件,可以用View进行包装。

1
2
3
4
5
6
7
8
9
10
11
12
13
<TouchableHighlight onPress={this._onPressButton.bind(this)} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>TouchableHighlight</Text>
</View>
</TouchableHighlight>

// 可点击的图片
<TouchableHighlight onPress={this._onPressButton}>
<Image
style={styles.button}
source={require('./myButton.png')}
/>
</TouchableHighlight>

TouchableNativeFeedback

仅限android。

TouchableOpacity

透明度变化。

TouchableWithoutFeedback

不带反馈效果的。

API

Share分享功能

1
2
3
4
5
6
import { Share } from 'react-native';
Share.share({ // 官方文档说android用message、ios用url,但经过我的测试最好都用url,因为分享到不同的app,获取的字段并不相同
title: url,
message: url,
url: url,
})

JSX语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用循环
<View>
{this.state.voices.map((voice, index) => {
return (
<Text key={`voice-${voice.id}`}>
{voice.text}
</Text>
)
})}
</View>

// 定义模板(自定义标签)
const InfoText = ({ text }) => ( // 其中text是模板的参数
<View style={styles.container}>
<Text style={styles.infoText}>{text}</Text>
</View>
)
<InfoText text="haofly"/> // 使用模板

样式stylesheet

  • 官方建议不要将stylesheet放在render函数中
  • 最好不同的组件使用不同的名称,不要全都用styles命名
  • 原生不支持scss那样的嵌套语法,好像也没有啥好用的嵌套方式,就是感觉原生就是不支持什么复杂的样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const page = StyleSheet.create({
container: {
flex: 1,
padding: 24,
alignItems: "center"
}
})

const typography = StyleSheet.create({
header: {
color: "#61dafb",
fontSize: 30,
marginBottom: 36
}
})

网络请求

React Native使用的网络请求是Fetch API,但是,统治js的http请求库明显是axios,所以我还是喜欢用axios,另外,网络请求天生就应该是异步的,这两个库都是不支持同步的。

1
2
3
// 安装npm install --save axios
import axios from 'axios';
axios.get('...').then((response)=>(console.log(response.data))); // 得到响应结果,不用像fetch那样responseJson了

Debug

  • 如果是真机,可以通过摇一摇弹出debug菜单,但是基本上没啥用,最有用的可能就是Chrome里面调试了,至少能看到打印出来的object的详情

  • LogBoxrelease/production中是自动禁用的

常用插件推荐

Awesome React Native

  • 包含很多的react native的插件扩展

customauth-react-native-sdk

  • torus sdk

  • 如果运行不起来可以试试它项目里面的example,虽然文档少了,但是那个example还是更新的挺及时的,照着看有没有遗漏的,我在1.0.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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // ios/Podfile,具体行数参考example中的配置
    use_modular_headers
    pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
    installer.pods_project.build_configurations.each do |config|
    # config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
    end

    installer.pods_project.targets.each do |target|
    if target.name == "web3.swift"
    target.build_configurations.each do |config|
    config.build_settings["SWIFT_INCLUDE_PATHS[sdk=iphonesimulator*]"] = "$(inherited) $(PODS_CONFIGURATION_BUILD_DIR)/BigInt $(PODS_CONFIGURATION_BUILD_DIR)/GenericJSON $(PODS_TARGET_SRCROOT)/web3swift/lib/**"
    config.build_settings["SWIFT_INCLUDE_PATHS[sdk=iphoneos*]"] = "$(inherited) $(PODS_CONFIGURATION_BUILD_DIR)/BigInt $(PODS_CONFIGURATION_BUILD_DIR)/GenericJSON $(PODS_TARGET_SRCROOT)/web3swift/lib/**"
    end
    end
    end

    // AppDelegate.m,我最开始就是点了登录后没反应,后来发现是它根本没有监听openURL
    - (BOOL)application:(UIApplication *)app
    openURL:(NSURL *)url
    options:(NSDictionary<NSString *, id> *)options {

    NSString *myString = url.absoluteString;

    NSLog(@"String to handle : %@ ", myString);
    if (@available(iOS 10.0, *)) {
    [RNCustomAuthSdk handle:myString];
    } else {
    // Fallback on earlier versions
    }

    // Your additional URL handling (if any) goes here.
    return NO;
    }


    // ios/xxx/Info.plist,添加url scheme
    <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLSchemes</key>
    <array>
    <string>torusapp</string>
    </array>
    </dict>

react-native-geolocation-service

  • 谷歌定位插件,能够获取当前的定位

  • 如果出现获取不到地理位置,经常提示timed out并且time out设置为很大依然报错,可以参考这个issueLocation request timed out most of the time,下载谷歌地图然后定位一下,再重新安装一下应用试试

  • 如果出现Location settings are not satisfied: 根据我的尝试,可能是因为国内或者说是因为小米手机的问题,ios和android得不同的设置才行:

    1
    2
    3
    4
    5
    Geolocation.getCurrentPosition(
    (position) => {console.log(position)},
    (error) => {console.log(error)},
    Platform.OS === 'ios' ? { enableHighAccuracy: true, timeout: 25000, maximumAge: 20000 } : { enableHighAccuracy: false, maximumAge: 20000, forceRequestLocation: true, forceLocationManager: true, distanceFilter: 250, accuracy: { android: 'balanced', ios: 'threeKilometers' } }
    );

react-native-async-storage

  • 能够用来持久化mobx等的状态,在应用退出后不会清空
  • React-native iOS, Async storage error: "Invalid key - must be at least one character. Key: 出现这个错误是因为在getItem/setItem的时候key的值为空,需要修改一下,注意如果key的值修改后可能需要重新build才能生效

react-native-bottom-sheet

  • 一个比较好用的底部弹出功能,drawer,抽屉
  • snapPoints: 定义弹出的区域的高度,这之外的地方不能点击
  • enablePanDownToClose: 向下滑自动关闭
  • 如果是多个sheet叠加显示,好像DOM后面的就是最上层

react-native-dotenv

react-native-config

  • react-native-configreact-native-dotenv更通用,不用为每个环境变量声明typescript,并且它支持不同的环境使用不同的环境变量

  • 使用.env文件来加载环境变量

  • 需要注意的是,它是有缓存的,如果变量更改了记得参考文档清理cache

  • 如果使用的是typescript,最好参考文档使用Option 2: specify types manually

react-native-drop-shadow

  • 拖动的时候的阴影

react-native-elements

  • element 的UI套件

react-native-fs

  • 文件操作,下载文件,保存文件

react-native-iap

  • 用于google play和apple store的内购组件
  • Android平台能够通过getProducts获取产品列表,但是购买的时候却报错That item is unavailable: 具体原因还未知,在github提交了discussion,但目前没有回复。最后不知道怎么就解决了,尝试过这些方法:
    1. 上传一个signed release到internal testing和closed testing,但是第一次上传审核时间有点久,且审核通过后可能也要等几小时才可以
    2. Google Play Console -> Setup -> API access: 打开了Play Android Developer API,应该和这个无关
    3. License testing得添加设备登录的google账号
    4. App -> Setup -> Advanced settings -> App availability设置为Published
    5. App -> Setup -> Advanced settings -> Managed Google Play设置为Turn on下面的留空就行

react-native-paper

  • material-ui在react-native平台的替代品,同样遵循material design,但是最后不推荐,集成的本来就不多,还不大好用
  • 在使用Menu.Item的时候,如果要自定义menu和整个container的高度,需要设置minHeight和maxHeight才行,不知道为啥container会默认设置为100,源码里没看到哪个地方有设置
  • ActivityIndicator就是一个loading图标,非常好用

react-native-picker

  • 滚动时间或者select选择器

react-native-qr-decode-image-camera

  • 至少从图片里面解析二维码只有这个好用点

react-native-share

  • 弹出原生的分享组件,例如分享airdrop,保存到文件夹
  • 触摸滚动组件,但是已经几年没维护了,且可以直接用原生的VirtualizedList替代

react-native-text-input-mask

  • 比如电话号码输入的mask模式
  • 如果出现TypeError: null is not an object (evaluating ‘RNTextInputMask’)in v3.0.0,需要添加这行配置到podfile文件: pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text', :modular_headers => true

@testing-library/react-native

  • 测试框架

性能优化

最重要的是将需要变化的状态细化到单独的组件,这样状态变化时就不会影响到其他不需要的地方

Touchable系列组件不能很好的响应

  • 通过requestAnimationFrame,可以让组件的透明度改变效果很快切换回来,而不会卡在那儿
1
2
3
4
requestAnimationFrame(() => {
this.doExpensiveAction();
});
}

开发原生相关问题

在真实设备上调试以及打包到真实设备

在真实设备上调试,只需要在XcodeRun到你自己连接的设备即可,这时候安装在手机上面的,是和电脑上面模拟器出来的一模一样,也能进行调试,但是断开usb后应用不能使用。如果要将应用直接整体打包到设备上面,看看真实使用的效果,可以按照这个教程进行设置https://facebook.github.io/react-native/docs/running-on-device.html,主要就是修改AppDelegate.m中的jsCodeLocation的值,将其改变成如下状态即可。

1
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

APP图标设置

参考Xcode中的图标设置,也只能在xcode中设置,即直接将图标拖如Images.xcassets

原生库

开发者会将很多原生库打包成一些静态库,或者由js直接封装好了的静态库。一般比较好的静态库都能够使用命令自动链接:react-native link 某已安装的具体库名,如果手动链接可以参考文档linking-libraries-ios

TroubleShooting

  • “:CFBundleIdentifier” Does Not Exist: 可能是因为你的代码依赖的是老的react native或者node版本或者xcode版本,可以执行以下命令升级依赖:react nativeupgrade

  • undefined is not an object evaluating React.PropTypes.string: 仍然是版本的问题,新版的已经将React.PropTypes移到单独的库了(prop-types)。需要注意的是React.PropTypes.func更改成了PropTypes.function了,其他的名字没有改,只是位置变了。

  • undefined is not an object(evalauating ‘WeChat.registerApp’): 引入react-native-wechat之后手动去link

  • No bundle url present: 启动的时候报错,有以下几种解决方案:

    • 全部关了以后,看看8081端口是否被占用,然后重新react-native run-ios
    • 上面方法多次尝试不行以后直接删除node_modules目录,重新安装依赖
  • isMounted(…) is deprecated warning: 目前来看,并没有什么解决方案。

  • 闪退: 有如下几种情况

  • _this._registerevents is not a function: 升级的时候没有顺便升级react-native-cli

  • cross-env: command not found: npm install cross-env

  • unable to load script from assets index.android.bundle: 这样做能够解决(来自于Stackoverflow):

    1
    2
    3
    4
    5
    6
    mkdir android/app/src/main/assets
    react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
    react-native run-android

    # 可以将上面的命令放到package.json的scripts中去,这样以后直接npm run android-linux即可
    "android-linux": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && react-native run-android"
  • **SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.**原因是没有定义android sdk的位置,首先下载android sdk或者安装android studio(会自动下载sdk),最后将地址写在local.properties文件或者直接设置为环境变量ANDROID_HOME

  • **com.android.builder.testing.api.DeviceException: No connected devices! **得去android studio把安卓模拟器打开

  • react-native run-android命令提示Android project not found. Maybe run react-native android first,但是执行react-native android却说命令没找到: 首先看当前目录有没有android文件夹,如果没有,那么使用react-native eject命令生成,如果有,那么就用android studio来运行一次,看看是不是有哪些基础环境没有安装

  • Invalid YGDirection ‘row’ should be one of: (inherit, ltr, rtl): 需要将<Flex direction="row"修改为<Flex flexDirection="row"

  • Print: Entry, ":CFBundleIdentifier", Does Not Exist 解决方法如下

    1
    2
    3
    4
    # 首先关闭XCode
    cd node_modules/react-native/third-party/glog-{X}.{X}.{X}/
    ./configure
    # 然后重新打开xcdoe即可
  • Text strings must be rendered within a component: 首先最基本的,文字必须在text组件里面,但这还是比较容易排查,而不好排查的情况一般是我们在做判断的时候没有使用布尔值,例如

    1
    2
    {icon && {icon}} // 这样会报错
    {!!icon && {icon}} // 将对象转换为布尔值即可
  • 输入框键盘挡住了部分视图: 这时候需要使用KeyboardAvoidingView来包装一下view,该组件可以自动根据键盘的高度,调整自身的height或底部的padding来避免遮挡,有时候也需要再配合ScrollView来使用,注意它可以不需要在整个页面外层包装,可以只包裹住form那部分即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import { useHeaderHeight } from '@react-navigation/elements'
    const height = useHeaderHeight()

    <KeyboardAvoidingView
    behavior={Platform.OS == "ios" ? "padding" : "height"}
    style={styles.container}
    keyboardVerticalOffset={height + 47} // 如果发现高度差那么一点可以这样设置
    >
    ...
    </KeyboardAvoidingView>

    <!--如果有时候KeyboardAvoingView不起作用,可以尝试https://www.npmjs.com/package/react-native-keyboard-aware-scroll-view,例如用react-native-google-places-autocomplete的时候-->
    <KeyboardAwareScrollView extraScrollHeight={75}>
    <GooglePlacesAutocomplete />
    </KeyboardAwareScrollView>
  • ARCHS[@]: unbound variable in Xcode 12或者YogaKit.modulemap not found: 需要把Build Settings -> Architectures -> Excluded Architecture设置成这样(来自Stackoverflow):

  • You must have a keystore.properties file in the /android/ folder or set the environments variables: Android目录下新建文件keystore.properities,内容如下即可:

    1
    2
    3
    4
    STORE_FILE=app.keystore
    KEY_ALIAS=app_alias
    STORE_PASSWORD=your_password
    KEY_PASSWORD=your_password
  • Android Studio build签名APK的时候报错index.js not found:可能是因为使用了typescript,文件现在是index.tsx,可以在build.gradle文件中指定entryFile:

    1
    2
    3
    4
    project.ext.react = [
    enableHermes: false, // clean and rebuild if changing
    entryFile: "index.tsx" // 指定为tsx文件
    ]
  • Android Studio报错:ERROR: Could not find method compile() for arguments: 可能是依赖的包在调用老的java的api,找到错误日志中的文件,将compile 'xxx'修改为implementation 'xxx'

  • Android Studio真机测试报错: Unable to load script. Make sure you’re either running a Metro server (run ‘react-natvie start’) or that your bundle ‘index.android.bundle’ is packaged correctly for release. 如果metro没打开就start,如果打开了,可以尝试执行这个命令: adb reverse tcp:8081 tcp:8081

  • **Could not resolve project :react-native-camera.**这是个已经没有维护的库了,参考doc,在android/app/build.gradle中添加missingDimensionStrategy 'react-native-camera', 'general'即可

  • xcrun: error: SDK “iphoneos” cannot be located: 尝试执行sudo xcode-select --switch /Applications/Xcode.app

  • Command PhaseScriptExecution failed with a nonzero exit code: 如果无法查看错误详情,可以尝试运行Archive,可能会显示错误详情,可能就是下面这个问题,node路径没有找到

  • React-Native env: node: No such file or directory: 尝试执行sudo ln -s "$(which node)" /usr/local/bin/node

  • **No simulator found with name “iPhone 13”**运行时可以指定模拟器的名称: yarn ios --simulator="iPhone 14"

    扩展阅读
  • 浅谈前端移动开发(Ionic与React Native)

  • 30天React Native学习

splash是一个轻量级的可执行脚本的server,并且提供了友好的API,而且能直接用docker进行部署,使用起来十分方便,对于那种必须通过js才能找到内容的爬虫来说简直是如虎添翼。

安装splash

最简单的方式,使用docker安装

1
2
docker pull scrapinghub/splash
docker run --name splash -p 5023:5023 -p 8050:8050 -p 8051:8051 -d scrapinghub/splash # 即可完成部署

其中,5023表示http8050表示https8051则是telnet

splash的配置

配置文件在/app/splash/defaults.py,如果是使用docker,那么直接修改该文件即可

1
2
# 在docker内部直接修改该文件/app/splash/defaults.py
PLUGINS_ENABLED = False # 是否开启flash的执行,默认是关闭了的

splash的API

splash的API是根据其HTTP的url来定义的,前缀都是docker的域名+ip。

render.html

例如http://127.0.0.1:8050/render.html?timeout=600&wait=10&proxy=socks5://192.168.0.6:1086&url=http://haofly.net

1
2
3
4
5
# 参数说明
url: 要请求的url
timeout: js执行超时时间,默认是30s
wait: 等待js执行完成的时间,默认是0,最大是10
proxy: 设置代理

render.har

获取所有的har数据,即请求该地址的时候该网页所有的请求以及headerbody信息。

好久没有认真的看雨了。

今晚下班回家,雨很大,即使撑着我的淘宝爆款超大雨伞也被打湿了裤腿,2017年第一次有了大雨滂沱的感觉,但是却突然发现对雨,我早已没有当初的那种感觉了。

犹记得那年我们都还很年少,闲庭屋外,邀几个小伙伴对雨而坐,看着公路上的汽车飞驰而过,溅起的水花是那样的干净澄澈。那时候,我们喜欢称这种雨为毛毛雨,因为雨很大很清澈的缘故,雨滴从几万米高空倾斜而下,与地面撞击后又反弹一定高度,大概十厘米高吧,看起来就像很多很多的白毛在地上跳跃。那时候天上是有真正的乌云的。下雨前,乌云密布,随着雨渐渐地减少,乌云也慢慢散去,最后云开雾散,要么天朗气清,要么彩虹悬挂,而绝不会像现在这样,无论雨来还是雨走,天空都是灰蒙蒙的一片,仿佛对地下的人们毫无感情。

小时候,我家后面有另一户人家,而我的窗外正好能看见他们相对较矮的老式瓦片屋檐。每次下雨或者有了小孩子特有心事的时候,就会在晚上关上灯,静静地听。其实,有心事的时候,你是听不进去雨的,因为雨滴声不是时钟那种滴答滴答的声音,而是滴滴滴滴……但是因为雨持续不断地跌落在瓦上,心扉仿佛也一直被雨滴敲打着,使你也无法安静地想自己的事情,只能任由那雨继续敲打我的心扉。就这样,我不开心门,她就不停息。然后,渐渐地进入了儿时的梦想。

可是,雨总会停,我们也终于长大了。

重庆的春天其实很短的,一般都是春夏秋冬随机播放几十天后,便匆匆地迎来了漫长的夏季。可是今年,重庆的雨仿佛特别多,还赖着不走,我也才有了这番心境。现在的心是静不下来的。雨天,路过的车飞啸而过,而你却只能慢慢走回家,那种感觉,真希望自己也能尽早有辆车,以后应该可以不用再淋雨了吧。每次下雨都很烦躁,这雨一直下,什么时候是个头呀,盼望着雨一停就出去玩儿,当然,我心里明明知道,即使不下雨我也只会宅在家里。雨不是原来的雨,人还是原来的人儿吗?

推荐小时候特别喜欢的一首歌《三月里的小雨》,现在听来,歌词其实挺有韵味的。

三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨为谁飘,小溪为谁流,带著满怀的凄清。
三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨陪伴我,小溪听我诉,可知我满怀的寂寞。
请问小溪,谁带我追寻,追寻那一颗爱我的心。

三月里的小雨,淅沥沥沥 沥沥 淅沥沥沥下个不停,
山谷里的小溪,哗啦啦啦 啦啦 哗啦啦啦流不停,
小雨陪伴我,小溪听我诉,可知我满怀的寂寞。
请问小溪,谁带我追寻,追寻那一颗爱我的心。
追寻那一颗爱我的心
追寻那一颗爱我的心

这是一本去年经常出现在我视线里面的一本书,被很多大V推荐过。首先,不得不说,书中的观点确实非常独到而又富有理论依据。用诸多的例子告诉了我们,一个人的成功离不开他所处的环境、家庭教育、机遇运气,甚至民族文化,当然也免不了10000小时的努力。这也正印证了我们的一句古话:天时地利人和。

单纯从本书的文笔上看,感觉同样没有多大趣味,对于普通的读者,几乎没有仔细读下去的欲望。不知道是此书本身的问题还是翻译的问题。译者的名字我是没听过,也没发现他有什么其他的作品。当然也不能就此下结论,即使是逐字翻译的,我也觉得此书的文笔依然不符合我的口味,每个例子都讲得挺详细,但是详细中给了人啰唆的感觉。当然,本来字数就不多,在不啰唆,可能就真没几页了😂。

我小时候一直很崇拜比尔盖茨,一个大学辍学的人也能创造这样一个IT帝国,那是多么地了不起的事业呀。我曾经也幻想,不上大学也一样能成功。直到年龄越来越大,离那个不切实际的梦越来越远的时候,我才意识到,我和他之间差了多少。家庭因素、时代因素,各种各样的因素我都比不上大他,甚至那一万小时的努力我也比不上他。他虽然辍学,但人家是什么学校,我又是什么学校呢。所以比尔盖茨,现在我只能像对待偶像那样看他,永远也不能望其项背。

算一下就知道,我的努力还远远不够。10000小时是什么概念?每天编程6小时,需要花大概5年;即使每天编程24小时,也要花一年多的时间。这还只是平均数,放假过节,谁没有个休息日呢。所以碌碌无为的普通人,连10000小时都做不到,还能跟人家比什么。拼爹?别说笑了,会认真看这本书的人,有几个人有实力拼爹?

说实话,这本书对我们的思想上的帮助非常大,极大地开阔了我们的眼界,但是对我们现实中的帮助缺寥寥无几。机遇很重要,但它终归是可遇不可求的。文化传承、时代背景、社会环境,也不是你我能够改变的。我们能做的依然只有那10000小时的努力,证视自己所处的环境,把握好每一个机遇,继续在我们这个时代奋斗着。

我始终相信努力奋斗的意义,我也始终相信越努力越幸运。

摘录

  • 所谓成功就是“优势积累”的结果
  • 成功就是坚持不懈,就是顽强不屈,就是别人花30秒钟就放弃的事你却花22分钟去思考的坚定信念。
  • 成长就是要持续不断地破坏现有平衡。
  • 为什么很多人不读书?因为他们从小到大一辈子从未感受过学习的力量……不是读书改变不了命运,是读了那些没用的书改变不了命运……读书就是隔时空与作者交流思想。

新家装修,需要组装两台电脑,一台低配NAS主机,一台高配游戏主机。等到新家装修完成,大概就能写完这篇文章啦。

硬盘

选购指导

对于我来说,硬盘只有容量和类型的区别,品牌之间的差距完全可以忽略不计。

机械硬盘(传统硬盘)

如果仅仅是做NAS用,那完全没必要上SSD,因为NAS里面的数据读写频率并不高,机械硬盘的稳定性离固态硬盘的稳定性相差并不大,所以综合考虑,机械硬盘是十分适合NAS的。目前我用的是一块2015年双十一买的7200转的希捷ST1000DM003硬盘,花了273元,现在价格是319元,果然硬盘涨价了呀。

功能分类

  • 桌面硬盘: 希捷尾数为DM001,WD蓝盘,黑盘系列,东芝P300系列等
  • 监控硬盘: 视频监控,要求持续不断地写入
  • NAS硬盘: 7*24小时无间断运行,静音,5400转以下极客。
  • 企业级硬盘: 7200转,

固态硬盘(SSD)

能极大地提高幸福感的东西。

  • M.2接口不一定就比SATA接口好,决定ssd性能的事主控芯片和NAND

移动硬盘

主板

选购指导

主板的选择一是要考虑机箱的大小,不同尺寸的主板对应不同尺寸的机箱,而机箱的大小一定要与家装相匹配。另一方面,主板还需要考虑扩展性与兼容性。比如我的NAS直接就集成了CPU和GPU,断了我扩展的后路,不过这正是我想要的,集成了就不用去选择CPU和GPU,强迫症的福音,而且集成过后完全不用考虑兼容问题。

主板规格

  • ATX:俗称“大板”,最流行最常见的一种主板,305mm x 244mm
  • MATX:“小板”,244mm x 244mm
  • ITX(Mini ITX): 170mm x 170mm,我选择的nas主板华擎j3455就是这个规格,考虑到不用加太多的扩展并且正好能利用到以前笔记本剩下的内存条

电源

  • 对于我那只有十几w的NAS主机来说,淘宝随便一个电源就能解决问题,不用考虑起稳定性,再差的电源也能支撑十几w的稳定运行。

机箱

  • 机箱的规格一定要和主板的规格匹配
  • 亚克力是一种不错的DIY机箱的材料
  • 电脑不用机箱也能跑

家庭影音

家庭影音分类

  • 5.1音箱: 由左前置音箱,中置音箱,右前置音箱,左环绕,右环绕和一个低音炮组成。左前置音箱,中置音箱,右前置音箱,左环绕,右环绕五只音箱播放的是完整音乐声道,低音炮,只负责150HZ以下的低音部分。各个声道的声音是完全独立的,各音箱的分工是左前置音箱,右前置音箱主要是播放影片中的背景音乐(各种音乐,枪炮声,各种效果声),中置音箱主要播放对白,让人感觉人说话是从电视或投影幕中出来,左环绕,右环绕主要是播放各种声效如,枪炮来自身后的声音,低音炮主要是播放枪炮,爆炸,风声等声音的朝中低音部分,即150HZ以下的声音。由于低音基本没有方向感,所以低音炮的低音是5声道中任意的。这样做就是为看电影的您营造出电影画面中的效果,举个例子,在《珍珠港》中飞机在荧幕上由左向右飞过,音箱发声的顺序是左前置——中置——右前置。这样给人的感觉就是一架飞机由左至右飞过。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)
  • 2.1音箱:这种音箱是电脑音箱中最多的,有两只高音小音箱和一个低音炮组成,两只高音音箱分别是左右2声道,低音炮的低音是不分左右共用的。d音箱小巧美观,易摆放,声音层次好,由于低音没有方向感,所以这种音箱看电影听音乐都非常不错。但是在购买的时候,最好购买低音喇叭较大的,这样低音效果更好。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)
  • 2.0音箱: 标准的立体声2.0音箱。其实就是2只音箱,没有单独的低音炮。这种音箱用于发烧音箱,监听音箱,舞台音箱等专业的录扩声设备都采用标准的立体声2声道音箱,但是作为电脑桌面音箱需要小巧,所以这种音箱摆放起来不好看,除专业和电脑发烧友以外很少使用。(摘录自http://blog.sina.com.cn/s/blog_64ddbfff0100h0p5.html)

终于看完编程之美的三部曲,其实他们三本书完全不是同一个类型同一个方向的著作,感觉完全是因为中文翻译的书名的原因才把他们放在一起。不过,对比前面两者,我觉得这本书才真正把哲学上的美向大家展示了出来,毕竟,将大数据进行可视化既是当今的流行趋势,又是对数据的直观展现,相比于冷冰冰的数据,可视化的图表才是真的让他们能美起来的东西。当然这也是我觉得这本书更有意思的主要原因。

《数据之美》这本书,给我们提供了丰富的例子来说明,数据可视化的深刻意义以及非常多的应用场景。我对数据挖掘是没有多大兴趣的,但是对爬虫的兴趣倒是很深。我一直保持一个自信:只要正常浏览器能看到的,那么我就能爬取到。所以,我写了很多爬虫。爬取汽车之家的车型车系,爬取房天下的房产数据,都是自娱自乐。也挺喜欢去解决爬虫的难点问题,我自己不知道爬取数据对自己有多大用,但我只是喜欢爬数据而已。

最后,推荐两个数据可视化的前端库,highcharts(可视化的先驱,功能可以说是最强大的)ECharts(百度出的可视化工具,功能强大,但是坑多,不是吹,是真的多),以及一些数据可视化的例子(http://www.datapointed.net/)

随着见闻的逐渐加深,接触或者了解过一些其他的优秀的文档编写工具,由于未深入研究过,所以,仅仅在这里进行简单的列举:

  • APIDOC: 支持大量编程语言的根据注释自动生成文档
  • ApiGen: PHP7的类文档自动生成工具
  • YApi: 极力推荐,开源工具,拥有其他项目的收费功能,并且也支持内网部署及二次开发
  • eolinker: 暂时未了解
  • showdoc: 暂未了解
  • mindoc: 暂未了解

swagger特点

swagger是我见过唯一还算将就的一个API文档制作与展示工具,其实最终都没让我找到一款完美的API文档编写工具。

swagger优点:

  • 一个文件就是一个文档
  • 只针对API,而不针对特定的语言的API,很多自动生成API的工具基本都是只针对特定的API的
  • 支持Json和yaml来编写API文档,并且支持导出为json、yaml、markdown等格式
  • 如果编写好了API了,可以自动生成相应的SDK,没错,可能你的API接口代码还没有开始写,它就能帮你制作相应的SDK了,而且支持几乎所有主流编程语言的SDK
  • 支持自动生成大量主流编程语言/框架的server端
  • 界面清晰,无论是editor的实时展示还是ui的展示都十分人性化,其他的API编写工具基本上都做不到这一点,如果自己仅仅用markdown来编写,又要纠结该如何展现,十分痛苦。
  • 官网有直接的demo,甚至都可以不用自己搞一套服务器

swagger缺点:

  • 貌似无法更改主题
  • 中英文的文档都比较少,其主要原因应该是官网的文档本身就不完善,只有针对不同模块儿的介绍,却没有针对具体用户的文档
  • yaml文件只能和API项目本身放在一起,这一点暂时还不知道有什么解决方案
阅读全文 »

这几个月我正在阅读的是编程之美系列书籍,《架构之美》是我看的第一部。全书只有前面两个部分吸引了我,后面的基本上是食之无味地略过。后来想想,此书成书于2009年,有些思想以及对编程的认识,在那个时候可能还是特别有吸引力的,但是拿到现在,可能并没有那么大的吸引力,一是因为这本书的后面部分讲得并不深入,另一个原因是新时代的语言满天飞,老式的语言对于我这种半吊子来说毫无兴趣。

书的前面部分主要讲了一些架构的基本概念和原则。比如,美丽的架构所展示的一些普遍的原则:

  • 一处一个事实:重复导致错误,所以应该避免
  • 自动传播:由一些构建工具支持
  • 架构包含构建:架构不仅包含运行时系统,而且必须包含它的构建方式
  • 最少量机制:实现某个功能的最佳方式要视情况而定,但是美丽的架构不会追求“最佳”。
  • 构建引擎
  • 增长的阶
  • 抵制熵增

以及相应的更完整的解释:

  • 功能性(Functionality):产品向他的用户提供哪些功能
  • 可变性(Changeability):软件将来可能需要哪些改变?哪些改变不太可能发生,不需要特别容易进行这些改变?
  • 性能(Performance):产品将达到什么性能?
  • 容量(Capacity):多少用户将并发使用该系统?该系统将为用户保存多少数据?
  • 生态系统(Ecosystem): 该系统将与其他系统进行哪些交互
  • 模块化(Modularity):
  • 可构建行(Buildability): 如何将软件构建为一组组建,并能够独立实现和验证这些组件?哪些组件应该复用其他的产品,哪些应该从外部供应商处获得
  • 产品化(Producibiity): 如果产品将以几种变体的形式存在,如何开发一个产品线,并利用这些变体的共性?产品线中的产品以怎样的步骤开发等
  • 安全心(Security)

概念性的东西其实到处都有,但是在第一部分里面,即使是讲述概念方面,作者的表达方式也是非常让人有读下去的欲望的。于是顺着作者的思路就来到了一个伟大软件架构的诞生的历程,不过那几个软件奇葩的名字还真是让人费解。好在作者用了最有效最真实的方法来讲述一个软件架构如何做到完美的。要想往完美的架构迈进,首先要做的就是承认,世界上没有完美的架构,只有在不断演化中,不断适应需求中,架构才能越来越完美。其实架构本身就已经很美了,每次我看到同事画的或是自己画的架构图,都觉得真美呀,特别是当自己画的架构图能够一下子让大家都看懂的时候。正如我在实际工作中所体验的一样,本书也认为架构的输出图是最重要的,有了图,我们的工程师才知道该做什么,才知道为什么要那样做。由于保密的问题,我肯定不会把公司内部的架构图放在这里,但是相信我,我们工程师画的每一张架构图,都是特别美的。

以前的我会认为编程是一件十分简单的事情,因为无论什么语言,只需要花两三天看一下基本的语法就能用那种语言写一个东西出来,但是在实际的工作中,我才明白,编程最重要的绝对不是编程语言,编程语言反而是最次要的,最重要的是如何根据当前的需求以及未来可能出现的需求而设计出的“最完美的架构”。

语录:

软件的架构其实是和公司的组织结构及开发流程相互影响的。当然大多数情况下是软件的架构是被动者。但好的软件架构设计原则反作用于组织机构及开发流程也不是不可能的。

没有完美的架构。架构师就是力求做一个务实的“平衡美人”。不能一边坐拥着间接、长远才见效、容易视而不见的幕后优点,一边又对为了实现前者随之带来的小小应付成本挑三拣四,这样很容易捡了芝麻丢了瓜。。。

好的架构就是要分离关注点,也即“庖丁解牛,分而治之”。降低耦合性,这样复杂性也随着降低了,让参与系统各个方面的开发测试人员只需了解自己需要了解的模块,不需要了解整个系统,就能并行地进行工作了。只有这样才能开发出超越了单个人智慧所能理解的复杂软件生态系统平台。对于复杂系统的大部分参与人员:“知其然,也要知所以然”未必适用。

构架在最初构想的时候,可以脱离实际,思考出解决问题的最佳途径,但是在实施过程中,必须要考虑细节。

架构是一个过程,而非一个结果。

但是,你仍然可以不必过多担心功能就开始设计架构。你关注的是需要满足的品质。

Fred Brooks说,概念完整性是架构最重要的特征:“最好是让系统反映一组设计思想,而不是让系统包含许多好的思想,而这些思想却彼此独立而不协调”(1995)

注意:软件架构不是一成不变的。需要时就改变它。要想做到可以修改,架构就必须保持简单

像一座建筑或一个城市的物理架构一样,系统的架构必须适应环境,利用该架构创建的工件将存在于该环境之中。

在每一种情况下,我们都会先探索所有可能性,然后再做决定。我们会在“最后可能的时刻”做出决定,即不做决定的代价超过了实现该特征的代价。尽管如果一开始就用Spring,有些事情我们可能会做得不一样,但在后来加入它也没有让我们受苦。在早期的迭代中,我们关注的是发现应用想成为什么样子,而不是Spring希望我们如何构建应用。

如果,在采取了所有让任务能够由单人处理的方法之后,架构任务仍然巨大而复杂,不能由一人来完成,那么产品肯定是太复杂了,以致不实用且不应构建。换言之,单个用户必须能够理解计算机的架构。如果计划的架构不能由一个人设计,那它也不能被一个人理解。(1997)

例如,如果我们请你来设计一个“基于Web的应用”,你首先问我们页面布局和导航树,还是问下面这些问题: ·谁提供应用主机托管?托管的环境有什么技术限制吗? ·你想运行在Windows服务器上还是在LAMP栈上? ·你想支持多少并发用户? ·应用需要怎样的安全性?有需要保护的数据吗?应用将运行在公网上还是在私有的内部网上? ·你能为这些答案排列优先级吗?例如,用户数是否比响应时间更重要?

软件架构师的首要关注点不是系统的功能。

架构的最主要产出是什么?我的答案是:图。这里面有两层含义:一层含义是如同建筑师描绘的蓝图一样,用于引导实施者;另一层含义是架构师头脑中清晰的目标系统。如果架构师头脑中没有系统清晰的图像,他是没有办法把它画出来的。