From 7e80911ab0753891f85631c205ed3e9633f8122e Mon Sep 17 00:00:00 2001 From: OS-ruialves Date: Mon, 16 Mar 2026 17:54:01 +0000 Subject: [PATCH] feat(android): add live updates provider api support - Update ReactNativeLiveUpdatesModule to support mock provider functionality - Update ReactNativePortalManager with live updates integration - Update MainApplication.kt to demonstrate mock provider setup - Include documentation for live updates mock implementation --- android/build.gradle | 10 +- .../ReactNativeLiveUpdatesModule.kt | 51 ++- .../reactnative/ReactNativePortalManager.kt | 92 +++++- .../liveupdates/MockLiveUpdatesManager.kt | 70 ++++ .../liveupdates/MockLiveUpdatesProvider.kt | 86 +++++ .../liveupdates/MockProviderExample.kt | 136 ++++++++ .../portals/reactnative/liveupdates/README.md | 86 +++++ .../MainApplication.kt | 13 +- example/src/App.tsx | 19 +- example/src/MockLiveUpdatesExample.tsx | 304 ++++++++++++++++++ 10 files changed, 840 insertions(+), 27 deletions(-) create mode 100644 android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesManager.kt create mode 100644 android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesProvider.kt create mode 100644 android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockProviderExample.kt create mode 100644 android/src/main/java/io/ionic/portals/reactnative/liveupdates/README.md create mode 100644 example/src/MockLiveUpdatesExample.tsx diff --git a/android/build.gradle b/android/build.gradle index 611fb6b..0d7ad2f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,8 +1,9 @@ buildscript { // Buildscript is evaluated before everything else so we can't use getExtOrDefault - def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["PortalsReactNative_kotlinVersion"] + def kotlin_version = "2.1.20" repositories { + mavenLocal() google() mavenCentral() } @@ -83,6 +84,7 @@ android { } repositories { + mavenLocal() mavenCentral() google() } @@ -93,9 +95,11 @@ dependencies { // For < 0.71, this will be from the local maven repo // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin //noinspection GradleDynamicVersion + implementation "io.ionic:live-updates-provider:LOCAL-SNAPSHOT" + implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "io.ionic:portals:0.13.0-rn.1" + // implementation "io.ionic:portals:0.13.0-rn.1" + implementation "io.ionic:portals:LOCAL-SNAPSHOT" implementation "io.ionic:liveupdates:0.5.+" } - diff --git a/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt b/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt index 5d21259..db11120 100644 --- a/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt +++ b/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt @@ -8,6 +8,7 @@ import io.ionic.liveupdates.data.model.FailResult import io.ionic.liveupdates.data.model.Snapshot import io.ionic.liveupdates.data.model.SyncResult import io.ionic.liveupdates.network.SyncCallback +import io.ionic.liveupdatesprovider.LiveUpdatesError import kotlinx.coroutines.* import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.callbackFlow @@ -21,24 +22,48 @@ internal object LiveUpdatesModule { ) fun syncOne(appId: String, context: Context, promise: Promise) { - LiveUpdateManager.sync( - context = context, - appId = appId, - callback = object : SyncCallback { - override fun onAppComplete(syncResult: SyncResult) { - promise.resolve(syncResult.toReadableMap()) - + // Check if there's a custom LiveUpdatesManager for this appId + val customManager = RNPortalManager.getLiveUpdatesManager(appId) + + if (customManager != null) { + // Use the custom manager's sync method + customManager.sync(object : io.ionic.liveupdatesprovider.SyncCallback { + override fun onComplete(result: io.ionic.liveupdatesprovider.models.SyncResult) { + // Convert provider SyncResult to the format expected by the bridge + val resultMap = WritableNativeMap() + resultMap.putBoolean("didUpdate", result.didUpdate) + resultMap.putString("appId", appId) + if (result.latestAppDirectory != null) { + resultMap.putString("latestAppDirectory", result.latestAppDirectory?.absolutePath) + } + promise.resolve(resultMap) } - override fun onAppComplete(failResult: FailResult) { - promise.resolve(failResult.toReadableMap()) + override fun onError(error: LiveUpdatesError.SyncFailed) { + promise.reject("SYNC_FAILED", error.message, error.cause) } + }) + } else { + // Fall back to the default LiveUpdateManager + LiveUpdateManager.sync( + context = context, + appId = appId, + callback = object : SyncCallback { + override fun onAppComplete(syncResult: SyncResult) { + promise.resolve(syncResult.toReadableMap()) - override fun onSyncComplete() { - // do nothing + } + + override fun onAppComplete(failResult: FailResult) { + promise.resolve(failResult.toReadableMap()) + } + + override fun onSyncComplete() { + // do nothing + } } - } - ) + ) + } } fun syncSome(appIds: ReadableArray, context: Context, promise: Promise) { diff --git a/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt b/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt index f01c559..4f4e029 100644 --- a/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt +++ b/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt @@ -4,6 +4,9 @@ import com.facebook.react.bridge.* import com.getcapacitor.Plugin import io.ionic.liveupdates.LiveUpdate import io.ionic.liveupdates.LiveUpdateManager +import io.ionic.liveupdatesprovider.LiveUpdatesManager +import io.ionic.liveupdatesprovider.LiveUpdatesRegistry +import io.ionic.liveupdatesprovider.models.ProviderConfig import io.ionic.portals.* import org.json.JSONArray import org.json.JSONException @@ -44,8 +47,18 @@ internal object RNPortalManager { private lateinit var reactApplicationContext: ReactApplicationContext private var usesSecureLiveUpdates = false + // Map to store custom LiveUpdatesManager instances by appId + private val liveUpdatesManagers = ConcurrentHashMap() + fun register(key: String) = manager.register(key) + /** + * Get a custom LiveUpdatesManager for the given appId, if one was registered. + */ + fun getLiveUpdatesManager(appId: String): io.ionic.liveupdatesprovider.LiveUpdatesManager? { + return liveUpdatesManagers[appId] + } + fun createPortal(map: ReadableMap): RNPortal? { val name = map.getString("name") ?: return null val portalBuilder = PortalBuilder(name) @@ -102,20 +115,81 @@ internal object RNPortalManager { assetMaps.forEach(portalBuilder::addAssetMap) - map.getMap("liveUpdate") - ?.let { readableMap -> - val appId = readableMap.getString("appId") ?: return@let null - val channel = readableMap.getString("channel") ?: return@let null - val syncOnAdd = readableMap.getBoolean("syncOnAdd") - Pair(LiveUpdate(appId, channel, usesSecureLiveUpdates), syncOnAdd) - } - ?.let { (liveUpdate, updateOnAppLoad) -> + map.getMap("liveUpdate")?.let { liveUpdateMap -> + val appId = liveUpdateMap.getString("appId") ?: return@let + val channel = liveUpdateMap.getString("channel") ?: return@let + val syncOnAdd = liveUpdateMap.getBoolean("syncOnAdd") + val providerId = liveUpdateMap.getString("providerId") + val providerConfigMap = liveUpdateMap.getMap("providerConfig") + + // Check if we should use the new LiveUpdatesManagerProvider approach + if (providerId != null && providerConfigMap != null) { + try { + // Get the provider from the registry + val provider = LiveUpdatesRegistry.resolve(providerId) + + if (provider == null) { + // Fall back to the traditional LiveUpdate approach + val liveUpdate = LiveUpdate(appId, channel, usesSecureLiveUpdates) + portalBuilder.setLiveUpdateConfig( + context = reactApplicationContext, + liveUpdateConfig = liveUpdate, + updateOnAppLoad = syncOnAdd + ) + return@let + } + + // Convert the providerConfig ReadableMap to a Map + // Filter out null values to match the expected type + val configDataMap = providerConfigMap.toHashMap() + .filterValues { it != null } + .mapValues { it.value as Any } + + // Add appId and channel to the config data + val configData = mutableMapOf( + "appId" to appId, + "channel" to channel, + "providerId" to providerId + ) + configData.putAll(configDataMap) + + // Create the ProviderConfig + val providerConfig = ProviderConfig(configData) + + // Create the manager using the provider + val manager = provider.createManager( + context = reactApplicationContext, + config = providerConfig + ) + + // Store the manager by appId so it can be retrieved for sync operations + liveUpdatesManagers[appId] = manager + + // Set the live updates manager on the portal builder + portalBuilder.setLiveUpdateManager( + context = reactApplicationContext, + liveUpdatesManager = manager, + updateOnAppLoad = syncOnAdd + ) + } catch (e: Exception) { + // Fall back to the traditional LiveUpdate approach + val liveUpdate = LiveUpdate(appId, channel, usesSecureLiveUpdates) + portalBuilder.setLiveUpdateConfig( + context = reactApplicationContext, + liveUpdateConfig = liveUpdate, + updateOnAppLoad = syncOnAdd + ) + } + } else { + // Fall back to the traditional LiveUpdate approach + val liveUpdate = LiveUpdate(appId, channel, usesSecureLiveUpdates) portalBuilder.setLiveUpdateConfig( context = reactApplicationContext, liveUpdateConfig = liveUpdate, - updateOnAppLoad = updateOnAppLoad + updateOnAppLoad = syncOnAdd ) } + } portalBuilder .addPlugin(PortalsPlugin::class.java) diff --git a/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesManager.kt b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesManager.kt new file mode 100644 index 0000000..0f83167 --- /dev/null +++ b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesManager.kt @@ -0,0 +1,70 @@ +package io.ionic.portals.reactnative.liveupdates + +import android.util.Log +import io.ionic.liveupdatesprovider.LiveUpdatesError +import io.ionic.liveupdatesprovider.LiveUpdatesManager +import io.ionic.liveupdatesprovider.SyncCallback +import io.ionic.liveupdatesprovider.models.SyncResult +import java.io.File +import kotlin.concurrent.thread + +/** + * Mock implementation of LiveUpdatesManager for testing purposes. + * Simulates async sync behavior with configurable success/failure scenarios. + */ +internal class MockLiveUpdatesManager( + private val appId: String, + private val channel: String, + private val latestAppDir: File, + private val shouldFail: Boolean, + private val failureDetails: String, + private val didUpdate: Boolean +) : LiveUpdatesManager { + + companion object { + private const val TAG = "MockLiveUpdatesManager" + private const val SIMULATED_DELAY_MS = 500L + } + + override fun sync(callback: SyncCallback?) { + Log.d(TAG, "Starting mock sync for appId: $appId, channel: $channel") + + // Simulate async behavior with a background thread + thread { + try { + // Simulate network delay + Thread.sleep(SIMULATED_DELAY_MS) + + if (shouldFail) { + Log.d(TAG, "Mock sync failed for appId: $appId - $failureDetails") + val error = LiveUpdatesError.SyncFailed(failureDetails, null) + callback?.onError(error) + } else { + Log.d( + TAG, + "Mock sync completed for appId: $appId, didUpdate: $didUpdate" + ) + + // Ensure the mock directory exists if didUpdate is true + if (didUpdate && !latestAppDir.exists()) { + latestAppDir.mkdirs() + } + + val result = SyncResult( + didUpdate = didUpdate, + latestAppDirectory = if (didUpdate) latestAppDir else null + ) + callback?.onComplete(result) + } + } catch (e: InterruptedException) { + Log.e(TAG, "Mock sync interrupted for appId: $appId", e) + val error = LiveUpdatesError.SyncFailed("Sync interrupted", e) + callback?.onError(error) + } + } + } + + override fun latestAppDirectory(): File? { + return if (latestAppDir.exists()) latestAppDir else null + } +} diff --git a/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesProvider.kt b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesProvider.kt new file mode 100644 index 0000000..c4faf57 --- /dev/null +++ b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockLiveUpdatesProvider.kt @@ -0,0 +1,86 @@ +package io.ionic.portals.reactnative.liveupdates + +import android.content.Context +import android.util.Log +import io.ionic.liveupdatesprovider.LiveUpdatesError +import io.ionic.liveupdatesprovider.LiveUpdatesManager +import io.ionic.liveupdatesprovider.LiveUpdatesProvider +import io.ionic.liveupdatesprovider.LiveUpdatesRegistry +import io.ionic.liveupdatesprovider.models.ProviderConfig +import java.io.File + +/** + * Mock implementation of LiveUpdatesProvider for testing purposes in React Native. + * This allows testing the live updates API without making actual network requests. + */ +class MockLiveUpdatesProvider private constructor() : LiveUpdatesProvider { + companion object { + private const val TAG = "MockLiveUpdatesProvider" + private const val PROVIDER_ID = "ionic-mock" + + val INSTANCE: MockLiveUpdatesProvider by lazy { MockLiveUpdatesProvider() } + private var isRegistered = false + + /** + * Initializes and registers the mock provider with the LiveUpdatesRegistry. + * This should be called in the Application onCreate() before any live updates are used. + */ + @JvmStatic + fun initialize() { + if (!isRegistered) { + Log.d(TAG, "Registering MockLiveUpdatesProvider") + LiveUpdatesRegistry.register(INSTANCE) + isRegistered = true + } + } + } + + override val id: String + get() = PROVIDER_ID + + @Throws(LiveUpdatesError.InvalidConfiguration::class) + override fun createManager( + context: Context, + config: ProviderConfig + ): LiveUpdatesManager { + val configData = config.data + + // Extract appId (required) + val appId = configData["appId"] as? String + ?: throw LiveUpdatesError.InvalidConfiguration( + "Mock provider requires 'appId' in config", + null + ) + + if (appId.trim().isEmpty()) { + throw LiveUpdatesError.InvalidConfiguration( + "Mock provider requires non-empty 'appId' in config", + null + ) + } + + // Extract optional parameters + val channel = configData["channel"] as? String ?: "production" + val shouldFail = configData["shouldFail"] as? Boolean ?: false + val failureDetails = configData["failureDetails"] as? String ?: "Mock sync failed" + val didUpdate = configData["didUpdate"] as? Boolean ?: false + + // For testing, create a mock directory path + // In a real scenario, this would point to actual app assets + val latestAppDir = File(context.filesDir, "mock_live_updates/$appId/$channel") + + Log.d( + TAG, + "Creating MockLiveUpdatesManager for appId: $appId, channel: $channel, shouldFail: $shouldFail" + ) + + return MockLiveUpdatesManager( + appId = appId, + channel = channel, + latestAppDir = latestAppDir, + shouldFail = shouldFail, + failureDetails = failureDetails, + didUpdate = didUpdate + ) + } +} diff --git a/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockProviderExample.kt b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockProviderExample.kt new file mode 100644 index 0000000..c034578 --- /dev/null +++ b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/MockProviderExample.kt @@ -0,0 +1,136 @@ +package io.ionic.portals.reactnative.liveupdates + +import android.content.Context +import android.util.Log +import io.ionic.liveupdatesprovider.LiveUpdatesRegistry +import io.ionic.liveupdatesprovider.SyncCallback +import io.ionic.liveupdatesprovider.models.ProviderConfig +import io.ionic.liveupdatesprovider.models.SyncResult +import io.ionic.liveupdatesprovider.LiveUpdatesError + +/** + * Example demonstrating how to use the MockLiveUpdatesProvider. + * This can be called from your Android application code for testing. + */ +object MockProviderExample { + private const val TAG = "MockProviderExample" + + /** + * Example 1: Successful sync with update + */ + fun testSuccessfulSync(context: Context) { + Log.d(TAG, "=== Testing Successful Sync ===") + + val config = ProviderConfig( + mapOf( + "appId" to "test-app-123", + "channel" to "production", + "didUpdate" to true, + "shouldFail" to false + ) + ) + + val provider = LiveUpdatesRegistry.resolve("ionic-mock") + if (provider == null) { + Log.e(TAG, "Mock provider not registered!") + return + } + + val manager = provider.createManager(context, config) + + manager.sync(object : SyncCallback { + override fun onComplete(result: SyncResult) { + Log.d(TAG, "✅ Sync successful!") + Log.d(TAG, " - Did update: ${result.didUpdate}") + Log.d(TAG, " - Latest dir: ${result.latestAppDirectory}") + } + + override fun onError(error: LiveUpdatesError.SyncFailed) { + Log.e(TAG, "❌ Sync failed: ${error.message}") + } + }) + } + + /** + * Example 2: Sync without update + */ + fun testNoUpdateSync(context: Context) { + Log.d(TAG, "=== Testing No Update Sync ===") + + val config = ProviderConfig( + mapOf( + "appId" to "test-app-456", + "channel" to "development", + "didUpdate" to false, + "shouldFail" to false + ) + ) + + val provider = LiveUpdatesRegistry.require("ionic-mock") + val manager = provider.createManager(context, config) + + manager.sync(object : SyncCallback { + override fun onComplete(result: SyncResult) { + Log.d(TAG, "✅ Sync successful!") + Log.d(TAG, " - Did update: ${result.didUpdate}") + Log.d(TAG, " - Latest dir: ${result.latestAppDirectory}") + } + + override fun onError(error: LiveUpdatesError.SyncFailed) { + Log.e(TAG, "❌ Sync failed: ${error.message}") + } + }) + } + + /** + * Example 3: Failed sync + */ + fun testFailedSync(context: Context) { + Log.d(TAG, "=== Testing Failed Sync ===") + + val config = ProviderConfig( + mapOf( + "appId" to "test-app-789", + "channel" to "staging", + "shouldFail" to true, + "failureDetails" to "Network timeout error" + ) + ) + + val provider = LiveUpdatesRegistry.require("ionic-mock") + val manager = provider.createManager(context, config) + + manager.sync(object : SyncCallback { + override fun onComplete(result: SyncResult) { + Log.d(TAG, "✅ Sync successful!") + Log.d(TAG, " - Did update: ${result.didUpdate}") + } + + override fun onError(error: LiveUpdatesError.SyncFailed) { + Log.e(TAG, "❌ Sync failed (expected): ${error.message}") + } + }) + } + + /** + * Run all tests + */ + fun runAllTests(context: Context) { + Log.d(TAG, "\n========================================") + Log.d(TAG, "Running Mock Provider Tests") + Log.d(TAG, "========================================\n") + + testSuccessfulSync(context) + Thread.sleep(600) // Wait for async completion + + testNoUpdateSync(context) + Thread.sleep(600) + + testFailedSync(context) + Thread.sleep(600) + + Log.d(TAG, "\n========================================") + Log.d(TAG, "Tests Complete") + Log.d(TAG, "========================================\n") + } +} diff --git a/android/src/main/java/io/ionic/portals/reactnative/liveupdates/README.md b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/README.md new file mode 100644 index 0000000..413044c --- /dev/null +++ b/android/src/main/java/io/ionic/portals/reactnative/liveupdates/README.md @@ -0,0 +1,86 @@ +# Mock Live Updates Provider + +A mock implementation of the Live Updates Provider API for testing in React Native Portals. + +## Quick Start + +### 1. Initialize the Provider + +In your `MainApplication.kt`: + +```kotlin +import io.ionic.portals.reactnative.liveupdates.MockLiveUpdatesProvider + +class MainApplication : Application() { + override fun onCreate() { + super.onCreate() + + // Initialize mock provider + MockLiveUpdatesProvider.initialize() + } +} +``` + +### 2. Use the Provider + +```kotlin +import io.ionic.liveupdatesprovider.LiveUpdatesRegistry +import io.ionic.liveupdatesprovider.models.ProviderConfig + +val config = ProviderConfig(mapOf( + "appId" to "my-app-id", + "channel" to "production", + "didUpdate" to true, // Simulate update available + "shouldFail" to false // Don't simulate failure +)) + +val provider = LiveUpdatesRegistry.require("ionic-mock") +val manager = provider.createManager(context, config) + +manager.sync(object : SyncCallback { + override fun onComplete(result: SyncResult) { + Log.d("MyApp", "Sync complete: didUpdate=${result.didUpdate}") + } + + override fun onError(error: LiveUpdatesError.SyncFailed) { + Log.e("MyApp", "Sync failed: ${error.message}") + } +}) +``` + +### 3. Run Example Tests + +```kotlin +import io.ionic.portals.reactnative.liveupdates.MockProviderExample + +// Run all test scenarios +MockProviderExample.runAllTests(context) +``` + +## Files + +- **MockLiveUpdatesProvider.kt**: Main provider implementation +- **MockLiveUpdatesManager.kt**: Manager that handles sync operations +- **MockProviderExample.kt**: Example usage and test scenarios + +## Configuration Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `appId` | String | *required* | App identifier | +| `channel` | String | "production" | Channel name | +| `didUpdate` | Boolean | false | Simulate update available | +| `shouldFail` | Boolean | false | Simulate sync failure | +| `failureDetails` | String | "Mock sync failed" | Error message | + +## Testing + +View logs with: +```bash +adb logcat -s MockLiveUpdatesProvider MockLiveUpdatesManager MockProviderExample +``` + +## See Also + +- [MOCK_LIVE_UPDATES.md](../../../../MOCK_LIVE_UPDATES.md) - Full documentation +- [Live Updates Provider SDK](https://github.com/ionic-team/live-updates-provider-sdk) diff --git a/example/android/app/src/main/java/com/portalsreactnativeexample/MainApplication.kt b/example/android/app/src/main/java/com/portalsreactnativeexample/MainApplication.kt index 0e6ff92..2876f4a 100644 --- a/example/android/app/src/main/java/com/portalsreactnativeexample/MainApplication.kt +++ b/example/android/app/src/main/java/com/portalsreactnativeexample/MainApplication.kt @@ -1,6 +1,7 @@ package com.portalsreactnativeexample import android.app.Application +import android.util.Log import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactHost @@ -9,8 +10,10 @@ import com.facebook.react.ReactPackage import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactNativeHost -import com.facebook.react.soloader.OpenSourceMergedSoMapping import com.facebook.soloader.SoLoader +import io.ionic.portals.reactnative.liveupdates.MockLiveUpdatesProvider +import io.ionic.portals.reactnative.liveupdates.MockProviderExample +import com.facebook.react.soloader.OpenSourceMergedSoMapping class MainApplication : Application(), ReactApplication { @@ -40,5 +43,13 @@ class MainApplication : Application(), ReactApplication { // If you opted-in for the New Architecture, we load the native entry point for this app. load() } + + // Initialize the mock live updates provider + Log.d("MainApplication", "Initializing MockLiveUpdatesProvider") + MockLiveUpdatesProvider.initialize() + + // Optionally run tests (comment out for production) + // Uncomment the line below to run tests on app startup + // MockProviderExample.runAllTests(this) } } diff --git a/example/src/App.tsx b/example/src/App.tsx index e7f5613..9dec297 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,7 +1,8 @@ /* eslint-disable */ import * as React from 'react'; import PubSubLabel from './PubSubLabel'; -import { StyleSheet, View } from 'react-native'; +import MockLiveUpdatesExample from './MockLiveUpdatesExample'; +import { StyleSheet, View, Button } from 'react-native'; import { PortalView, addPortal, @@ -24,6 +25,8 @@ var portal: Portal = { }; export default function App() { + const [showMockExample, setShowMockExample] = React.useState(false); + // If using the old deprecated API, you can use the following code to register web vitals: // const [ready, setReady] = React.useState(false); // const setupPortal = async () => { @@ -43,6 +46,11 @@ export default function App() { // setReady(true); // }); // }, []); + + if (showMockExample) { + return ; + } + const initialNumber = 0; return ( @@ -61,6 +69,12 @@ export default function App() { }, }} /> + +