Skip to content

Commit 02cbec6

Browse files
dmytrorykunfacebook-github-bot
authored andcommitted
Add react-native-test-library package (facebook#43068)
Summary: This diff adds `react-native-test-library` package. It contains native module and native component example, and targets both the new and the old architecture. It has structure similar to many OSS React Native libraries, and is supposed to be used to test the integration with third-party libraries. It is integrated with RNTester as the **OSS Library Example** screen. {F1457510909} **Change Background** tests native commands. **Set Opacity** tests native props. **Get Random Number** tests native module. Changelog: [Internal] Differential Revision: D50793835
1 parent eca78c3 commit 02cbec6

22 files changed

+901
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
require 'json'
7+
8+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
9+
10+
Pod::Spec.new do |s|
11+
s.name = 'OSSLibraryExample'
12+
s.version = package['version']
13+
s.summary = package['description']
14+
s.description = package['description']
15+
s.homepage = package['homepage']
16+
s.license = package['license']
17+
s.platforms = min_supported_versions
18+
s.author = 'Meta Platforms, Inc. and its affiliates'
19+
s.source = { :git => package['repository'], :tag => "#{s.version}" }
20+
21+
s.source_files = 'ios/**/*.{h,m,mm,cpp}'
22+
23+
install_modules_dependencies(s)
24+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Important
2+
This package is for testing only. It is a subject to frequent change. It does not represent the recomended structure for React native libraries. It should not be used as a referece for such purposes.
3+
4+
## Building
5+
```
6+
yarn install
7+
yarn build
8+
npx react-native codegen
9+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
buildscript {
9+
ext.safeExtGet = {prop, fallback ->
10+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
11+
}
12+
repositories {
13+
google()
14+
gradlePluginPortal()
15+
}
16+
dependencies {
17+
classpath("com.android.tools.build:gradle:7.0.4")
18+
}
19+
}
20+
21+
apply plugin: 'com.android.library'
22+
apply plugin: 'kotlin-android'
23+
24+
android {
25+
compileSdkVersion safeExtGet('compileSdkVersion', 31)
26+
27+
defaultConfig {
28+
minSdkVersion safeExtGet('minSdkVersion', 23)
29+
targetSdkVersion safeExtGet('targetSdkVersion', 31)
30+
}
31+
32+
sourceSets {
33+
main {
34+
java.srcDirs += ['src', 'java']
35+
}
36+
}
37+
}
38+
39+
repositories {
40+
maven {
41+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
42+
url "$projectDir/../node_modules/react-native/android"
43+
}
44+
mavenCentral()
45+
google()
46+
}
47+
48+
dependencies {
49+
implementation 'com.facebook.react:react-native:+'
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.reactnative.osslibraryexample">
3+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.reactnative.osslibraryexample
9+
10+
import com.facebook.fbreact.specs.NativeSampleModuleSpec
11+
import com.facebook.react.bridge.ReactApplicationContext
12+
import com.facebook.react.bridge.ReactContextBaseJavaModule
13+
import com.facebook.react.bridge.ReactMethod
14+
import com.facebook.react.module.annotations.ReactModule
15+
16+
@ReactModule(name = NativeSampleModuleSpec.NAME)
17+
class NativeSampleModule(reactContext: ReactApplicationContext?) :
18+
ReactContextBaseJavaModule(reactContext) {
19+
20+
override fun getName(): String = NAME
21+
22+
companion object {
23+
const val NAME = "NativeSampleModule"
24+
}
25+
26+
@ReactMethod
27+
public fun getRandomNumber(): Int {
28+
return (0..99).random()
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.reactnative.osslibraryexample
9+
10+
import com.facebook.react.ReactPackage
11+
import com.facebook.react.bridge.NativeModule
12+
import com.facebook.react.bridge.ReactApplicationContext
13+
import com.facebook.react.uimanager.ViewManager
14+
15+
class OSSLibraryExamplePackage : ReactPackage {
16+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
17+
listOf(NativeSampleModule(reactContext))
18+
19+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> =
20+
listOf(SampleNativeComponentViewManager())
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.reactnative.osslibraryexample
9+
10+
import android.graphics.Color
11+
import com.facebook.react.bridge.ReadableArray
12+
import com.facebook.react.common.MapBuilder
13+
import com.facebook.react.module.annotations.ReactModule
14+
import com.facebook.react.uimanager.SimpleViewManager
15+
import com.facebook.react.uimanager.ThemedReactContext
16+
import com.facebook.react.uimanager.ViewProps
17+
import com.facebook.react.uimanager.annotations.ReactProp
18+
import com.facebook.react.viewmanagers.SampleNativeComponentManagerInterface
19+
20+
/** Legacy View manager (non Fabric compatible) for {@link SampleNativeView} components. */
21+
@ReactModule(name = SampleNativeComponentViewManager.REACT_CLASS)
22+
internal class SampleNativeComponentViewManager :
23+
SimpleViewManager<SampleNativeView>(), SampleNativeComponentManagerInterface<SampleNativeView> {
24+
25+
override fun getName(): String = REACT_CLASS
26+
27+
@ReactProp(name = ViewProps.OPACITY, defaultFloat = 1f)
28+
override fun setOpacity(view: SampleNativeView, opacity: Float) {
29+
super.setOpacity(view, opacity)
30+
}
31+
32+
@SuppressLint("ColorParseColorUsageIssue")
33+
@ReactProp(name = ViewProps.COLOR)
34+
fun setColor(view: SampleNativeView, color: String) {
35+
view.setBackgroundColor(Color.parseColor(color))
36+
}
37+
38+
@ReactProp(name = "cornerRadius")
39+
fun setCornerRadius(view: SampleNativeView, cornerRadius: Float) {
40+
if (cornerRadius !== null) {
41+
view.setCornerRadius(cornerRadius)
42+
}
43+
}
44+
45+
override fun createViewInstance(reactContext: ThemedReactContext): SampleNativeView =
46+
SampleNativeView(reactContext)
47+
48+
@SuppressLint("ColorParseColorUsageIssue")
49+
override fun changeBackgroundColor(view: SampleNativeView, color: String) {
50+
view.setBackgroundColor(Color.parseColor(color))
51+
}
52+
53+
override fun getExportedViewConstants(): Map<String, Any> = mapOf("PI" to 3.14)
54+
55+
override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
56+
return MapBuilder.builder<String, Any>()
57+
.put(
58+
"onColorChanged",
59+
MapBuilder.of(
60+
"phasedRegistrationNames",
61+
MapBuilder.of("bubbled", "onColorChanged", "captured", "onColorChangedCapture")))
62+
.build()
63+
}
64+
65+
@SuppressLint("ColorParseColorUsageIssue")
66+
override fun receiveCommand(view: SampleNativeView, commandId: String, args: ReadableArray?) {
67+
if (commandId.contentEquals("changeBackgroundColor")) {
68+
val sentColor: Int = Color.parseColor(args?.getString(0))
69+
view.setBackgroundColor(sentColor)
70+
}
71+
}
72+
73+
@SuppressLint("ColorParseColorUsageIssue")
74+
@Suppress("DEPRECATION") // We intentionally want to test against the legacy API here.
75+
override fun receiveCommand(view: SampleNativeView, commandId: Int, args: ReadableArray?) {
76+
when (commandId) {
77+
COMMAND_CHANGE_BACKGROUND_COLOR -> {
78+
val sentColor: Int = Color.parseColor(args?.getString(0))
79+
view.setBackgroundColor(sentColor)
80+
}
81+
}
82+
}
83+
84+
override fun getCommandsMap(): Map<String, Int> =
85+
mapOf("changeBackgroundColor" to COMMAND_CHANGE_BACKGROUND_COLOR)
86+
87+
companion object {
88+
const val REACT_CLASS = "SampleNativeComponent"
89+
const val COMMAND_CHANGE_BACKGROUND_COLOR = 42
90+
}
91+
92+
@ReactProp(name = "values")
93+
override fun setValues(view: SampleNativeView, value: ReadableArray?) {
94+
val values = mutableListOf<Int>()
95+
value?.toArrayList()?.forEach { values.add((it as Double).toInt()) }
96+
view.emitOnArrayChangedEvent(values)
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.reactnative.osslibraryexample
9+
10+
import android.graphics.Color
11+
import android.graphics.drawable.GradientDrawable
12+
import android.view.View
13+
import com.facebook.react.bridge.Arguments
14+
import com.facebook.react.bridge.ReactContext
15+
import com.facebook.react.bridge.WritableArray
16+
import com.facebook.react.bridge.WritableMap
17+
import com.facebook.react.uimanager.ThemedReactContext
18+
import com.facebook.react.uimanager.UIManagerHelper
19+
import com.facebook.react.uimanager.events.Event
20+
import com.facebook.react.uimanager.events.RCTEventEmitter
21+
22+
class SampleNativeView(context: ThemedReactContext) : View(context) {
23+
private var currentColor = 0
24+
private var background: GradientDrawable = GradientDrawable()
25+
private val reactContext: ReactContext = context.reactApplicationContext
26+
27+
override fun setBackgroundColor(color: Int) {
28+
if (color != currentColor) {
29+
background.setColor(color)
30+
currentColor = color
31+
emitNativeEvent(color)
32+
setBackground(background)
33+
}
34+
}
35+
36+
fun setCornerRadius(cornerRadius: Float) {
37+
background.cornerRadius = cornerRadius
38+
setBackground(background)
39+
}
40+
41+
private fun emitNativeEvent(color: Int) {
42+
val event = Arguments.createMap()
43+
val hsv = FloatArray(3)
44+
Color.colorToHSV(color, hsv)
45+
val backgroundColor =
46+
Arguments.createMap().apply {
47+
putDouble("hue", hsv[0].toDouble())
48+
putDouble("saturation", hsv[1].toDouble())
49+
putDouble("brightness", hsv[2].toDouble())
50+
putDouble("alpha", Color.alpha(color).toDouble())
51+
}
52+
53+
event.putMap("backgroundColor", backgroundColor)
54+
55+
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, "onColorChanged", event)
56+
}
57+
58+
fun emitOnArrayChangedEvent(ints: List<Int>) {
59+
val newIntArray = Arguments.createArray()
60+
val newBoolArray = Arguments.createArray()
61+
val newFloatArray = Arguments.createArray()
62+
val newDoubleArray = Arguments.createArray()
63+
val newYesNoArray = Arguments.createArray()
64+
val newStringArray = Arguments.createArray()
65+
val newObjectArray = Arguments.createArray()
66+
val newArrayArray = Arguments.createArray()
67+
68+
for (i in ints) {
69+
newIntArray.pushInt(i * 2)
70+
newBoolArray.pushBoolean(i % 2 == 1)
71+
newFloatArray.pushDouble(i * 3.14)
72+
newDoubleArray.pushDouble(i / 3.14)
73+
newYesNoArray.pushString(if (i % 2 == 1) "yep" else "nope")
74+
newStringArray.pushString(i.toString())
75+
76+
val latLon = Arguments.createMap()
77+
latLon.putDouble("lat", -1.0 * i)
78+
latLon.putDouble("lon", 2.0 * i)
79+
newObjectArray.pushMap(latLon)
80+
81+
val innerArray: WritableArray = Arguments.createArray()
82+
innerArray.pushInt(i)
83+
innerArray.pushInt(i)
84+
innerArray.pushInt(i)
85+
newArrayArray.pushArray(innerArray)
86+
}
87+
88+
val payload =
89+
Arguments.createMap().apply {
90+
putArray("values", newIntArray)
91+
putArray("boolValues", newBoolArray)
92+
putArray("floats", newFloatArray)
93+
putArray("doubles", newDoubleArray)
94+
putArray("yesNos", newYesNoArray)
95+
putArray("strings", newStringArray)
96+
putArray("latLons", newObjectArray)
97+
putArray("multiArrays", newArrayArray)
98+
}
99+
100+
val reactContext = context as ReactContext
101+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
102+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
103+
val event = OnIntArrayChangedEvent(surfaceId, id, payload)
104+
105+
eventDispatcher?.dispatchEvent(event)
106+
}
107+
108+
inner class OnIntArrayChangedEvent(
109+
surfaceId: Int,
110+
viewId: Int,
111+
private val payload: WritableMap
112+
) : Event<OnIntArrayChangedEvent>(surfaceId, viewId) {
113+
override fun getEventName() = "topIntArrayChanged"
114+
115+
override fun getEventData() = payload
116+
}
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
module.exports = {
9+
presets: [['module:@react-native/babel-preset', {disableStaticViewConfigsCodegen: false}]],
10+
};

0 commit comments

Comments
 (0)