React Native快速入门:构建你的第一个APP
上周五晚上,我正窝在MacBook前用Cursor敲着一个Node.js中间件——没错,作为一个重度Cursor用户,我已经离不开这个AI搭档了。自从两年前加入这个组,从写纯前端到搞混合开发,再到如今天天和原生桥接打交道,我的键盘都快磨出火星子了。但那天,产品老大突然甩来一句话:“下周三前,搞个iOS和Android都能跑的Demo给客户看,React Native,你行的。” 我差点把手中的冰美式喷出来。
被逼上梁山,不如顺势起飞。
其实我对RN(React Native)早有耳闻,但一直没动真格。毕竟在我们这种“能用Web就不用App”的团队里,移动端优先级常年垫底。直到去年双11期间,我们的H5页面在低端安卓机上白屏三秒,产品经理当场暴走:“用户体验!知道什么叫用户体验吗?!” 于是,跨端原生渲染成了政治正确。而我,这个平时只用Mac写代码、Windows仅用于测试(还经常蓝屏)的底层原理爱好者,被迫扛起了这面大旗。
踩坑初体验:从“Hello World”到“WTF”
初始化项目时,我以为就是 npx react-native init MyApp 一气呵成。结果光是Xcode版本、Android SDK路径、Node版本冲突就折腾了两小时。最离谱的是,模拟器启动后直接报错:
Invariant Violation: "main" has not been registered.
我当场愣住——这不就是最基础的模板吗?后来才发现,是因为我同时开了Metro服务和旧项目的终端,端口冲突导致打包失败。重启大法好,但内心已经想砸键盘。
不过话说回来,一旦跑起来,那丝滑感真香。JSX写界面,热重载秒级反馈,比我在Xcode里改个颜色要等编译三分钟强太多。而且,得益于React的组件化思维,UI拆分特别自然。
写个真实的“产品”:天气小助手
为了不被产品经理再吐槽“Demo太假”,我决定做个稍微像样的功能:一个根据定位显示当地天气的小应用。虽然简单,但涉及权限、网络请求、平台适配,够练手了。
第一步:初始化 + 权限配置
npx react-native init WeatherBuddy
然后,分别处理iOS和Android的定位权限。
iOS:在 ios/WeatherBuddy/Info.plist 中添加:
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取位置以显示当地天气</string>
Android:在 android/app/src/main/AndroidManifest.xml 添加:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
这里有个坑:Android 12+ 需要用 ACCESS_COARSE_LOCATION + ACCESS_FINE_LOCATION 双权限,否则 getCurrentPosition 直接静默失败。我当时调试半天才发现日志里有一行小字:“denied due to missing coarse permission”。运维同事路过看了一眼说:“你这不就是典型的权限降级失败嘛?” 我:……谢谢,现在我知道了。
第二步:核心逻辑实现
我用了 @react-native-community/geolocation 获取位置,配合 axios 请求免费天气API(别问,问就是经费有限)。
// components/WeatherCard.tsx
import Geolocation from '@react-native-community/geolocation';
import axios from 'axios';
const WeatherCard = () => {
const [weather, setWeather] = useState<any>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 请求定位权限(省略权限检查逻辑)
Geolocation.getCurrentPosition(
async (position) => {
const { latitude, longitude } = position.coords;
try {
const res = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=YOUR_KEY&units=metric`
);
setWeather(res.data);
} catch (err) {
console.error('天气API炸了', err);
// 这里应该兜底,比如显示默认城市
} finally {
setLoading(false);
}
},
(error) => {
console.warn('定位失败', error.message);
setLoading(false);
// 用户可能拒绝权限,得友好提示
},
{ enableHighAccuracy: true, timeout: 15000 }
);
}, []);
if (loading) return <Text>正在加载天气...</Text>;
if (!weather) return <Text>获取天气失败,请重试</Text>;
return (
<View style={styles.card}>
<Text style={styles.city}>{weather.name}</Text>
<Text style={styles.temp}>{Math.round(weather.main.temp)}°C</Text>
<Text>{weather.weather[0].description}</Text>
</View>
);
};
注意:不要在真实项目里把API Key硬编码! 我这是为了演示。实际应该用环境变量或后端代理,不然你的Key很快会被爬虫刷爆——别问我怎么知道的。
第三步:平台差异处理
RN号称“Learn Once, Write Anywhere”,但现实是“You write once, debug everywhere”。
比如 iOS 的定位弹窗是系统级的,用户点了“仅使用期间允许”就能用;但 Android 上,不同厂商对后台定位限制不同,有的甚至要手动去设置里开“高精度定位”。为此,我专门封装了一个 useLocationPermission Hook,内部根据 Platform.OS 做差异化处理。
还有样式问题。iOS 默认字体是 San Francisco,Android 是 Roboto,字号表现略有差异。我最后统一用 PixelRatio.getFontScale() 微调,再配合 Platform.select:
const styles = StyleSheet.create({
temp: {
fontSize: Platform.select({ ios: 48, android: 44 }),
fontWeight: '600',
}
});
性能与体验:别让用户觉得“这是个套壳网页”
上线前,测试妹子发来灵魂拷问:“为什么第一次打开要等3秒?你们不是原生吗?”
哦,因为默认的Bundle加载策略是冷启动全量加载。解决方案有两个:
- 启用Hermes引擎(RN 0.60+默认开启):大幅减少JS解析时间。
- 代码分割 + 懒加载:虽然RN官方不支持动态import,但可以用
React.lazy+ 自定义加载器实现模块懒加载。
我在 android/app/build.gradle 确认了Hermes已开启:
project.ext.react = [
enableHermes: true // 👈 关键!
]
iOS那边则在 Podfile 里确保 Hermes 被包含:
use_react_native!(
:hermes_enabled => true
)
实测启动时间从3.2s降到1.4s,测试妹子终于露出了笑容。
发布上架:另一场修行
你以为写完代码就完了?Too young.
- iOS:要注册Apple Developer账号(99刀/年),配置Provisioning Profile,处理各种证书错误。有一次我换了新Mac,忘了迁移钥匙串,Xcode疯狂报错“no valid signing identities”,差点哭出来。
- Android:要生成签名APK,配置
keystore.properties,还要过Google Play的审核(比如隐私政策链接)。
我们最后用 eas build(Expo Application Services)简化流程,一条命令云端构建,省去本地环境烦恼。虽然有点贵,但比起自己搭CI/CD,值了。
开发心得:技术分享的终极意义
回过头看,这个小项目从“被逼无奈”到“真香现场”,让我深刻体会到:
- RN不是银弹,但确实是性价比之选:对于中低复杂度的业务场景(比如我们这种数据展示型App),它能用70%的Web开发效率,达到90%的原生体验。
- 平台差异永远存在:别信“一次编写到处运行”,做好为两个平台分别调试的心理准备。
- 工具链决定幸福感:强烈推荐搭配TypeScript + ESLint + Prettier + Cursor。尤其是Cursor,当我写到
Geolocation.getCurrentPosition时,它自动补全了完整的错误处理回调模板,省下我查文档十分钟。
| 维度 | Web App | React Native | 原生 |
|---|---|---|---|
| 开发速度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ |
| 性能 | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 平台能力 | ⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 维护成本 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
当然,如果你要做高性能游戏或重度动画,还是老老实实写原生吧。但对我们这种“产品需求变比翻书快”的团队来说,RN简直是救命稻草——上周五提的需求,今天就能给客户演示,老板看了直呼“高效”。
所以,别再犹豫了。装好Node、Xcode、Android Studio(祝你好运),然后:
npx react-native init YourFirstApp
然后,让Cursor帮你写第一行代码。相信我,一旦你尝过AI结对编程的甜头,就再也回不去了。
后记:这篇文章写完时,已经是凌晨两点。我合上MacBook,看了眼手机——天气小助手居然还在后台默默跑着,温度显示准确。那一刻,所有的debug痛苦都值得了。毕竟,我们写的不是代码,是产品,是用户手中的体验。

评论 0