2017-12-30 @sunderls
大家好,这是welogger app开发系列第三篇文章。
距离第二篇文章发布已经一个月过去了,这一个月年末各种琐事比较烦。实际上,welogger已经通过了AppleStore review,可以下载了,点击这里。
但是注册的话,需要有key。 目前只能通过内部渠道获得key,如果想加入的话可以尝试联系可能已经加入的同学,或者follow 我们的官方账号 @we_are_loggers,可能在不久之后会随机发出key。
这篇文章总结一些遇到的问题吧。
react-native 51开始有<SafeAreaView>
,可惜文档里面没有怎么叙述,有兴趣的可以google搜索一下。
import { SafeAreaView } from 'react-native';
也许是我没有怎么理解透彻,在welogger里面用了自定义的fixed tab,用起来不是很顺心。所以最后决定用了 /react-native-iphone-x-helper
welogger中hide了所有的默认tab,然后在顶部和底部的固定位置的组建中,判断是否是iphoneX,如果是的话加入额外的padding。比如这是welogger的顶部tab的stylesheet
header: {
justifyContent: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
borderBottomWidth: 0.2,
borderBottomColor: '#aaa',
...ifIphoneX({
paddingTop: 40,
height: 80
}, {
paddingTop: 20,
height: 60
})
},
react-navigation中的TabNavigator有默认的tab,但是用起来不太开心,不自由。
welogger想要一种没有那么明显的tab,最终采用了自定义的方式,实现起来也不麻烦,大概就是一个可以config icon和callback的组件,比如这样:
<Header leftIcon="icon-left" rightIcon="icon-left" tapLeft={...} tapRight={...} />
这其实不算一个tab,只是一个有点像tab的导航而已,因为它作为页面的一部分被显示, 在页面切换的时候会随着发生位置变换,没有原生tab那种比较好的切换动画,不过这感觉不是啥大问题,以后有时间研究透了再修改也行。w
上一篇文章中我说到页面结构是:
经过实际测试,发现这需有一些改进的地方,最终版如下:
Base页面初始化是调用init API,如果报错让登录的话就是没有登录,否则就按照init api的数据渲染。
嗯,redux-navigation的props转换到了redux state,所以需要更换redux的dispatch来处理页面切换跳转。
比如跳转到详情页:
import { NavigationActions } from 'react-navigation';
this.props.dispatch(NavigationActions.navigate({
routeName: 'Detail',
params: { id: item.id, title: item.title}
}));
比如返回到上一界面或者关闭modal
this.props.dispatch(NavigationActions.back());
react-native环境下可以直接使用标准API navigator.geolocation.getCurrentPosition
,但是,要注意缓存设置,不然位置移动不会体现在location信息中。 具体看这里
navigator.geolocation.getCurrentPosition((pos) => {
// ...
}, (error) => {
if (error.PERMISSION_DENIED) {
Alert.alert('', t('error.access.geo'));
}
reject(error);
}, {
maximumAge: 1000 // disable cache
});
图像的缓存也要注意,可以看facebook官网。https://facebook.github.io/react-native/docs/images.html
welogger暂时偷懒,直接用一个全局的loading indicator layer,实现也比较简单。就用redux store管理一下还没有resolve的request数就行
// action
export const loadingStart = () => {
return {
type: 'LOADING',
delta: 1
};
}
export const loadingEnd = () => {
return {
type: 'LOADING',
delta: -1
};
}
// reducer
export default function loading(count = 0, action) {
switch (action.type) {
case 'LOADING':
return count + action.delta;
}
return count;
}
// api
get() {
store.dispatch(loadingStart())
fetch(...)
.then(() => {
store.dispatch(loadingEnd())
...
})
.catch((e) => {
store.dispatch(loadingEnd())
...
}};
}
// view
{ this.pros.loading > 0 && <Loading > }
react-native有一个全局环境变量可以用来检测是否是开发环境,这就是__DEV__
,可以用来做一些简单的配置区分。
上一篇文章中用的是react-native-image-picker, 但是这个library不支持多图选择,所以后来换成了react-native-image-crop-picker,感觉还不错。
注意在最终build时候,需要将这个library添加到xcode的embedded libraries,否则会出现crash现象。 具体看这里: https://github.com/ivpusic/react-native-image-crop-picker/issues/253#issuecomment-283600340
welogger用的是react-native-i18n,用起来比较简单,没啥大问题。
import I18n from 'react-native-i18n';
import en from './locales/en';
import ja from './locales/ja';
import zh from './locales/zh';
I18n.fallbacks = true;
I18n.translations = {
en,
ja,
zh
};
export const t = (...params) => {
return I18n.t(...params);
};
export default I18n;
// view
<Text>{t('label.connect')}</Text>
如果是只用一个<Text>
的话,它会是一个矩形,如果设置背景颜色的话,没有字的部分也会有颜色。所以如果想要实现inline的效果的话,需要套用<Text>
react-native的文档中有说明,当用嵌套过后会使用iOS的NSAttributedString。
这里真是没有web页面方便,如果输入框处于页面下半部分的话,键盘很容易挡住输入框。这里需要监听键盘的出现和消失,然后调整输入框的位置。看起来麻烦,实际上还好,具体可以参考这篇文章https://medium.freecodecamp.org/how-to-make-your-react-native-app-respond-gracefully-when-the-keyboard-pops-up-7442c1535580
之前用的是AsyncStorage,发现网上各种吐槽其不安全,索性就改为了keychain,welogger用的是 react-native-keychain。
import * as Keychain from 'react-native-keychain';
const getToken = async ()=> {
const cred = await Keychain.getGenericPassword();
return cred && cred.password || '';
}
welogger采用的是sequelize作为orm,个人感觉node的orm真是没有php之类的做得好。sequelize也是各种麻烦,比如不支持TIMESTAMP(welogger用的INT)之类的。
最近遇到的一个问题是,如何在migration中查询sql进行数据修改,这需要用到queryInterface.sequelize.query
,以下是调用例子:
module.exports = {
up: async function (queryInterface, Sequelize) {
const allLogs = await queryInterface.sequelize.query(`
Select * from logs
`, { type: Sequelize.QueryTypes.SELECT});
await Promise.all(allLogs.map((log) => {
//...
}));
},
具体可以看这里: https://github.com/sequelize/sequelize/issues/313
应用开发差不多了,然后更新下icon吧。
我花了些时间考虑icon,原谅我没有多少艺术细胞。最终设计好了过后用的是这个网站Icon Generator for Corona SDK生成了iOS所需的各种size,感觉非常方便。
然后就build出ipa,然后提交到itunesconnect了。
送审第二天就被review & reject了,被说了两个问题:
然后第二次提交赶上美国圣诞节,提交第三天审核通过, oh yeah。
最近被老婆大人安利了Nulbarich这个刚出的乐队,貌似最近谜一样的冉冉升起,听了一下确实非常风格特别谜一样的魔性,虽然唱的是英语还是日语已经完全混在一起听不懂了。w
这里推荐他们的一首It's Who We Are。 也比较切合 welogger的价值观。祝大家新年愉快!