Android 上架应用商店
由于隐私问题被拒绝
国内某些应用商店会提示 「非服务所必需,存在若干SDK未经用户许可读取个人隐私信息(ANDROID-ID)」。
究其原始,是 expo-application
在获取 ANDROID_ID
。
// node_modules/expo-application/src/Application.ts
export const applicationId: string | null = ExpoApplication
? ExpoApplication.applicationId || null
: null;
// node_modules/expo-application/android/src/main/java/expo/modules/application/ApplicationModule.kt
constants["androidId"] = Settings.Secure.getString(mContext.contentResolver, Settings.Secure.ANDROID_ID)
解决方案
用固定的数值替换掉获取 ANDROID_ID
的代码即可。
Modal
中的 toast
层级会被 Modal
覆盖
使用 react-native-root-siblings
包裹 Modal
的内容
<Modal
isVisible={show}
onBackdropPress={() => {
setShow(false);
}}
onBackButtonPress={() => {
setShow(false);
}}
onModalHide={() => {
setAddNewProp(false);
// setVisible(true);
}}
animationIn={"slideInUp"}
animationOut={"slideOutDown"}
className={"m-0 justify-end"}
useNativeDriverForBackdrop={false}
swipeDirection={["down"]}
onSwipeComplete={() => {
setShow(false);
}}
onModalShow={() => textInputRef.current?.focus()}
avoidKeyboard={true}
>
<RootSiblingParent>
<View className={"h-full w-full flex-row items-center justify-start"}>
</View>
</RootSiblingParent>
</Modal>
TextInput
即使设置了 textAlign="center"
游标也会在最后边
添加 numberOfLines
和 multiline
属性
<TextInput
ref={textInputRef}
className={"flex-1"}
placeholder={"请输入"}
value={text}
onChangeText={setText}
textAlign={"center"}
numberOfLines={1}
multiline
/>
页面中同时存在多个 Modal
会在 iOS 中卡死
这是 react-native
中的一个 bug,具体解决方案是在 Modal
的 onModalHide
回调中显示另外的 Modal
I can't show multiple modals one after another
Unfortunately right now react-native doesn't allow multiple modals to be displayed at the same time. This means that, in react-native-modal, if you want to immediately show a new modal after closing one you must first make sure that the modal that your closing has completed its hiding animation by using the onModalHide prop.
I can't show multiple modals at the same time
See the question above. Showing multiple modals (or even alerts/dialogs) at the same time is not doable because of a react-native bug. That said, I would strongly advice against using multiple modals at the same time because, most often than not, this leads to a bad UX, especially on mobile (just my opinion).
iOS 返回应用崩溃
支付跳转到第三方引用:微信、支付宝,支付完成后,APP 闪退,错误信息为:
NSInvalidArgumentException: Application tried to present modally a view controller <RCTModalHostViewController: 0x10b693460> that is already being presented by <UIViewController: 0x109e25db0>.
这个问题是由 react-native-modal
导致的,具体原因是跳转的时候,对话框还展示着。解决方案也很明确:确保跳转的时候,对话框关闭。
const first = () => {
setShowModal(false);
setTimeout(() => {
then();
}, 1000);
};
TextInput 类型为文本时的键盘处理
在 iOS 下,可以通过 enterKeyHint
或者 returnKeyType
来与键盘进行交互,让其展示对应的快捷按键。比如让数字键盘展示一个 Done
的按钮,让键盘缩回。
但是对于文本类型的输入框来说。同样也能控制回车键的交互,但是达不到对应的需求,比如输入完成时缩回键盘。
对于这种情况可以通过 inputAccessoryViewID
属性配合 InputAccessoryView
使用,对整个键盘进行处理。
<TextInput inputAccessoryViewID="Done" />
<InputAccessoryView nativeID="Done">
<View className={"flex-row items-center bg-white py-3 px-6 border-t border-t-[#F3F3F3]"}>
<View className="flex-1" />
<TouchableOpacity
onPress={Keyboard.dismiss}
>
<Text className={"text-base font-medium text-[#4E83E4]"}>完成</Text>
</TouchableOpacity>
</View>
</InputAccessoryView>
Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release
确保 Android Emulator 里边的网络连接正常!
打包时提示 error: style attribute 'attr/*** not found
* What went wrong:
Execution failed for task ':xxx:verifyReleaseResources'.
> A failure occurred while executing com.android.build.gradle.tasks.VerifyLibraryResourcesTask$Action
> Android resource linking failed
ERROR: /path/to/project/node_modules/xxx/android/build/intermediates/merged_res/release/values/values.xml:1587: AAPT: error: style attribute 'attr/statusBarBackground (aka com.xxx:attr/statusBarBackground)' not found.
在项目对应的 src/main/res/values/attrs.xml
添加对应项即可。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="statusBarBackground" format="reference|color"/>
</resources>
资源引用
有些时候需要引入其他资源,对于这些资源文件,通常只需要使用其内容即可。对于这些资源,直接引用会报错。要正确获取其内容,需要执行以下步骤。
确保文件能被打包资源识别
通常 React Native 项目会使用 ~Metro bundler~ 那么只需要在 metro.config.js
文件中加入对应内容即可。
const config = getDefaultConfig(__dirname);
// 需要识别的文件扩展
config.resolver.assetExts.push('ext');
module.exports = config;
引入资源文件
加入了上述配置之后,就可以像 import
其他文件一样 import f from 'file.ext'
。
对于 webpack 来说,使用 raw-loader 就可以获取到文件的内容了,但是 Metro 中,执行上述代码,获取的只是模块的 module id
。还需要采取其它步骤。
获取文件内容
要获取文件内容需要引入额外的两个包: expo-asset
和 expo-file-system
。
安装完上面的包之后,就可以完成模块的下载和文件内容的读取了
from(Asset.loadAsync(module)).pipe(
switchMap(([{ localUri }]) =>
iif(
() => localUri != null,
defer(() =>
from(readAsStringAsync(localUri)).pipe(
//content is here!
map((content) => content),
),
),
of(''),
),
),
);
Android 打包长时间卡住
一直能正常打包的脚本,最近抽风,卡在特定的步骤
<=========----> 73% EXECUTING [10m 20s]
> IDLE
> IDLE
> IDLE
> IDLE
> :app:createBundleReleaseJsAndAssets
> IDLE
> IDLE
> IDLE
通过日志和抓包发现是在打包的时候,请求了某一服务,服务的连通性出了问题。通过 hosts
将此域名指向了 127.0.0.1
问题解决了。
Fragment 中获取 ReactContext
import androidx.fragment.app.Fragment
import com.facebook.react.ReactApplication
import com.facebook.react.ReactInstanceManager
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.modules.core.DeviceEventManagerModule
class XXXFragment : Fragment() {
private lateinit var reactContext: ReactContext
private lateinit var reactInstanceManager: ReactInstanceManager
override fun onAttach(context: Context) {
super.onAttach(context)
reactInstanceManager =
activity?.application?.let {
(it as ReactApplication).reactNativeHost.reactInstanceManager
}!!
reactContext = reactInstanceManager.currentReactContext as ReactContext
}
private fun sendEvent(reactContext: ReactContext, eventName: String, params: WritableMap?) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
.emit(eventName, params)
}
}
View config getter callback for component MyNativeModule
must be a function (received undefined
).
一个已经开发完成的 React Native 原生模块加载的时候突然报错:View config getter callback for component MyNativeModule
must be a function (received undefined
). 尝试了各种方法也没有找到原因和解决方法。使用 create-react-native-library
创建了一个新的模块之后,对比了一下文件,果然发现了不同的地方。老的模块的 package.json
中比新创建的模块中的多了
"devDependencies": {
"react": "18.2.0",
"react-native": "0.74.3"
}
再对比了一下主项目中的 react 和 react-native 的版本,发现主项目中的 react-native 版本为0.74.5
。在删除了模块 package.json
中的 devDependencies
之后,功能恢复如初。
未完待续~