[英]requireNativeComponent was not found in UIManager
I know this question has been asked many times but all the questions refers to integrating a third party dependency in react-native
app but in my case it is because of my own native code and I am having issues on how to fix it.我知道这个问题已经被问过很多次了,但是所有的问题都是指在react-native
应用程序中集成第三方依赖项,但就我而言,这是因为我自己的本机代码,我在如何修复它时遇到了问题。 I am using react-native
0.69我正在使用react-native
0.69
Here is snippet of my code这是我的代码片段
CealScanQrView.kt
class CealScanQrView(context: Context): FrameLayout(context) {
...
//Contains all the logic of integrating camerax, check below code repo to see the full source code
...
}
CealScanQrFragment.kt
class CealScanQrFragment: Fragment() {
private lateinit var cealScanQrView: CealScanQrView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
cealScanQrView = CealScanQrView(requireNotNull(context))
return cealScanQrView // this CustomView could be any view that you want to render
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// do any logic that should happen in an `onCreate` method, e.g:
cealScanQrView.setUpCamera(requireActivity())
}
override fun onDestroy() {
super.onDestroy()
cealScanQrView.destroyCamera()
}
}
CealScanQrViewManager.kt
class CealScanQrViewManager(
private val reactContext: ReactApplicationContext
) : ViewGroupManager<FrameLayout>() {
private val cealScanQrView = "CealScanQrView"
private val topChange = "topChange"
private val phasedRegistrationNames = "phasedRegistrationNames"
private val bubbled = "bubbled"
private val onChange = "onChange"
private val create = "create"
companion object {
private const val COMMAND_CREATE = 1
}
private var propWidth: Int? = null
private var propHeight: Int? = null
override fun getName() = cealScanQrView
override fun createViewInstance(reactContext: ThemedReactContext) = FrameLayout(reactContext)
override fun getCommandsMap() = mapOf("create" to COMMAND_CREATE)
override fun receiveCommand(root: FrameLayout, commandId: String?, args: ReadableArray?) {
super.receiveCommand(root, commandId, args)
val reactNativeViewId = requireNotNull(args).getInt(0)
when (commandId?.toInt()) {
COMMAND_CREATE -> createFragment(root, reactNativeViewId)
}
}
private fun createFragment(root: FrameLayout, reactNativeViewId: Int) {
val parentView = root.findViewById<ViewGroup>(reactNativeViewId)
setupLayout(parentView)
val myFragment = CealScanQrFragment()
val activity = reactContext.currentActivity as FragmentActivity
activity.supportFragmentManager
.beginTransaction()
.replace(reactNativeViewId, myFragment, reactNativeViewId.toString())
.commit()
}
private fun setupLayout(view: View) {
Choreographer.getInstance().postFrameCallback(object: Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
manuallyLayoutChildren(view)
view.viewTreeObserver.dispatchOnGlobalLayout()
Choreographer.getInstance().postFrameCallback(this)
}
})
}
@ReactPropGroup(names = ["width", "height"], customType = "Style")
fun setStyle(view: FrameLayout, index: Int, value: Int) {
if (index == 0) propWidth = value
if (index == 1) propHeight = value
}
private fun manuallyLayoutChildren(view: View) {
// propWidth and propHeight coming from react-native props
val width = requireNotNull(propWidth)
val height = requireNotNull(propHeight)
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY))
view.layout(0, 0, width, height)
}
override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
return mapOf(
topChange to mapOf(
phasedRegistrationNames to mapOf(
bubbled to onChange
)
)
)
}
}
On the JS
side在JS
方面
I created a CealScanQrViewManager.tsx
file我创建了一个CealScanQrViewManager.tsx
文件
import {requireNativeComponent} from 'react-native';
export const CealScanQrViewManager = requireNativeComponent(
'CealScanQrViewManager',
);
In App.tsx在 App.tsx 中
const createFragment = (viewId: number | null) =>
UIManager.dispatchViewManagerCommand(
viewId,
// we are calling the 'create' command
UIManager.CealScanQrViewManager.Commands.create.toString(),
[viewId],
);
const App = () => {
const isDarkMode = useColorScheme() === 'dark';
const [isCameraPermissionGranted, setIsCameraPermissionGranted] =
useState(false);
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
const ref = useRef(null);
useEffect(() => {
requestCameraPermission();
}, []);
useEffect(() => {
if (isCameraPermissionGranted) {
const viewId = findNodeHandle(ref.current);
createFragment(viewId);
}
}, [isCameraPermissionGranted]);
const requestCameraPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.CAMERA,
{
title: 'Cool Photo App Camera Permission',
message:
'Cool Photo App needs access to your camera ' +
'so you can take awesome pictures.',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
setIsCameraPermissionGranted(true);
} else {
console.log('Camera permission denied');
}
} catch (err) {
console.warn(err);
}
};
const readQr = async (data: any) => {
console.log(data.nativeEvent.qrCode);
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
{isCameraPermissionGranted ? (
<CealScanQrViewManager
style={{
// converts dpi to px, provide desired height
height: PixelRatio.getPixelSizeForLayoutSize(200),
// converts dpi to px, provide desired width
width: PixelRatio.getPixelSizeForLayoutSize(200),
}}
ref={ref}
onChange={readQr}
/>
) : (
<View style={{flex: 1, backgroundColor: 'red'}} />
)}
</SafeAreaView>
);
};
As soon as I grant the camera permission I get error saying一旦我授予相机权限,我就会收到错误消息
requireNativeComponent CealScanQrViewManager was not found in UIManager
Something of a stab-in-the-dark answer, but I think a correct one: the official guide to native components has you register a view manager, which is a class that overrides getName
to return a fixed string, and then pass that same string to requireNativeComponent
.有点刺眼的答案,但我认为一个正确的答案:本机组件的官方指南让您注册一个视图管理器,这是一个 class 覆盖getName
以返回固定字符串,然后传递相同的字符串到requireNativeComponent
。
In the repository you linked, those names do not match.在您链接的存储库中,这些名称不匹配。 You requireNativeComponent('CealScanQrViewManager')
, but register it as "CealScanQrView"
.您requireNativeComponent('CealScanQrViewManager')
,但将其注册为"CealScanQrView"
。 As the official guide explains,正如官方指南解释的那样,
Name returned by
getName
is used to reference the native view type from JavaScript.getName
返回的名称用于引用来自 JavaScript 的原生视图类型。
If the name does not match, no wonder looking up the type fails.如果名称不匹配,难怪查找类型失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.