Skip to content

About

No description, website, or topics provided.

Resources

Code of conduct

Stars

45 stars

Watchers

7 watching

Forks

Repository files navigation

jwplayer-react-native

Version NPM version License

⚠️ This README is for jwplayer-react-native version 1.0.0 and higher, for previous versions from the original author, Chaim Paneth via Orthodox Union, see react-native-jw-media-player. Beginning with version 0.2.0, this library uses JWX's JWPlayerKit (iOS) and SDK 4 (Android).


Prerequisites | Installation | Usage | Advanced Topics | Contributions | Issues


The jwplayer-react-native library is a bridge that enables using the native JWX Android and iOS SDKs in React Native applications.

sample sample sample



Prerequisites

Before installing and using the library, you need the following items:



Installation

Android | iOS

Android

Follow these steps to add the library to your Android project:

  1. From the project directory in terminal, add the jwplayer-react-native library. You can use npm or yarn.

    npm: npm i @jwplayer/jwplayer-react-native --save

    yarn: yarn add @jwplayer/jwplayer-react-native

  2. In android/build.gradle, add the JWX Maven repository inside the allprojects block.

    allprojects {
        repositories {
            ...
            maven {
                url 'https://mvn.jwplayer.com/content/repositories/releases/'
            }

If you are using EXPO, then an alternative way to the above so that you don't have to re-add it to android/build.grade every time you do: ```npx expo prebuild --clean``

Install expo-build-properties plugin: npx expo install expo-build-properties

and then add to app.json

    "plugins": [
      ... (your other plugins go here)
      [
        "expo-build-properties",
        {
          "android": {
            "extraMavenRepos": [
              {
                "url": "https://mvn.jwplayer.com/content/repositories/releases/"
              }
            ]
          }
        }
      ]
    ],

For more details and guidance regarding configuration and requirements, see the JWX Android SDK documentation.


iOS

Follow these steps to add the library to your iOS project:

  1. From the project directory in terminal, add the jwplayer-react-native library. You can use npm or yarn.

    npm: npm i @jwplayer/jwplayer-react-native --save

    yarn: yarn add @jwplayer/jwplayer-react-native

  2. Change the directory to the iOS folder of your React Native project.

    cd ios/
    
  3. Install the iOS dependencies with CocoaPods.

    pod install
    

Important

iOS is moving from CocoaPods to Swift Package Manager. JWPlayerKit 4.28.2 is the final iOS SDK version published to CocoaPods, and wrapper 1.9.1 is the last release that installs it through CocoaPods. Later iOS SDK versions are published only through Swift Package Manager, and future wrapper releases will require it. If your iOS app still uses CocoaPods for this wrapper, plan to migrate to Swift Package Manager before taking a wrapper release after 1.9.1.

Migrating to Swift Package Manager (React Native 0.88+)

React Native 0.88 can build iOS apps with Swift Package Manager instead of CocoaPods. The next wrapper release (the first after 1.9.1) ships an ios/Package.swift for React Native's SPM autolinking. Until it is published, use the Example app in this repo (which is built this way) as the reference.

  1. Upgrade your app to React Native 0.88 or later.
  2. In your ios/ folder, run npx react-native spm --deintegrate (React Native's migration command), then build from the .xcodeproj.
  3. Keep the stub ios/Podfile the migration leaves behind; the React Native CLI uses it to find the iOS project.
  4. Community libraries that don't ship a Package.swift need one generated with npx react-native spm scaffold and kept with patch-package (see Example/patches).

On this path Google IMA and Google Cast are always included, which adds to your app's size, and the minimum iOS version is 16.0 (Google Cast's Swift package requires it). Because Cast is always linked, add the Info.plist values listed under iOS Casting. React Native's Swift Package Manager support is still marked experimental by React Native.

The dependency paths in ios/Package.swift assume React Native's standard autolinking layout, with this package installed at node_modules/@jwplayer/jwplayer-react-native directly under your app root (next to the app's ios/ folder). A monorepo, hoisted, or otherwise non-standard node_modules location changes that depth and the package will not resolve React Native.

For more details and guidance regarding configuration and requirements, see the JWX iOS SDK documentation.



Usage

The following example shows how you can enhance your React Native application by seamlessly integrating the multimedia playback functionalities of the JWX mobile SDKs.

Follow these steps to configure the media playback experience in your app:

  1. Use the following example as a guide to configure the media playback experience. Be sure to remove all instances of ... from the code.
...

import JWPlayer, { JWPlayerState } from '@jwplayer/jwplayer-react-native';

...

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  player: {
    flex: 1,
  },
});

...

const playlistItem = {
  title: 'Track',
  mediaId: -1,
  image: 'http://image.com/image.png',
  description: 'My beautiful track',
  startTime: 0,
  file: 'http://file.com/file.mp3',
  tracks: [
    {
      file: 'http://file.com/english.vtt',
      label: 'en',
      default: true
    },
    {
      file: 'http://file.com/spanish.srt',
      label: 'es'
    }
  ],
  sources: [
    {
      file: 'http://file.com/file.mp3',
      label: 'audio'
    },
    {
      file: 'http://file.com/file.mp4',
      label: 'video',
      default: true
    }
  ]
}

const config = {
  license:
    Platform.OS === 'android'
      ? 'YOUR_ANDROID_SDK_KEY'
      : 'YOUR_IOS_SDK_KEY',
  backgroundAudioEnabled: true,
  autostart: true,
  styling: { // only (mostly) compatible with iOS
    colors: {
      timeslider: {
        rail: "0000FF",
      },
    },
  },
  playlist: [playlistItem],
}

...

async isPlaying() {
  const playerState = await this.JWPlayer.playerState();
  return playerState === JWPlayerState.JWPlayerStatePlaying;
}

...

render() {

...

<View style={styles.container}>
  <JWPlayer
    ref={p => (this.JWPlayer = p)}
    style={styles.player}
    config={config}
    onBeforePlay={() => this.onBeforePlay()}
    onPlay={() => this.onPlay()}
    onPause={() => this.onPause()}
    onIdle={() => console.log("onIdle")}
    onPlaylistItem={event => this.onPlaylistItem(event)}
    onSetupPlayerError={event => this.onPlayerError(event)}
    onPlayerError={event => this.onPlayerError(event)}
    onBuffer={() => this.onBuffer()}
    onTime={event => this.onTime(event)}
    onLoaded={event => this.onLoaded(event)}
    onFullScreen={() => this.onFullScreen()}
    onFullScreenExit={() => this.onFullScreenExit()}
  />
</View>

...

}
  1. Define config.license with your Android or iOS JWX license key.
  2. Define config.playlist with the media to play in the player.
  3. (Optional) Define the other values of the config prop.

ℹ️ See Props for all the available config prop fields.

ℹ️ See Legacy Readme for all the available config prop fields when using a legacy configuration.


Example Project

This repository contains the Example project. This project showcases several basic implementations of the <JWPlayer> view and can be used as a resource while working with the jwplayer-react-native library:

  • Test pull requests (PRs) or modifications
  • Experiment with the available media playback features
  • Validate your configurations in a known, working application
  • Demonstrate issues within a sanitary environment when submitting bugs

Follow these steps to run the example project:

  1. Checkout this repository.

  2. From the Example directory, run yarn or npm i.

  3. From the Example/ios directory, install the iOS dependencies.

    pod install
    
  4. In Xcode,open RNJWPlayer.xcworkspace.

  5. In App.js, within the config prop, add your JWX SDK license key.

  6. Build and run the app for your preferred platform.

    yarn android
    

    OR

    yarn ios
    

ℹ️ You can also build and run the app with specific react-native commands.

ℹ️ With Xcode 27, yarn ios fails because the React Native CLI tries to open Simulator.app from inside Xcode.app, where it no longer ships. Build and launch with Xcode directly, or from Example/ios:

xcrun simctl boot <SIMULATOR_UDID>
xcodebuild -workspace RNJWPlayer.xcworkspace -scheme RNJWPlayer -configuration Debug -destination id=<SIMULATOR_UDID> build
xcrun simctl install <SIMULATOR_UDID> ~/Library/Developer/Xcode/DerivedData/RNJWPlayer-*/Build/Products/Debug-iphonesimulator/RNJWPlayer.app
xcrun simctl launch <SIMULATOR_UDID> com.jwplayer.RNJWPlayer

Start Metro first with yarn start from Example.



Configuration

The library now features a unified configuration system that provides consistent, type-safe configuration across both iOS and Android platforms.

📚 Documentation

Quick Example

import JWPlayer, { JWPlayerConfig } from '@jwplayer/jwplayer-react-native';

const config: JWPlayerConfig = {
  license: 'YOUR_LICENSE_KEY',
  file: 'https://example.com/video.m3u8',
  autostart: true,
  advertising: {
    client: 'dai',
    imaDaiSettings: {
      videoId: 'tears-of-steel',
      cmsId: '2528370'
    }
  }
};

export default () => (
  <JWPlayer config={config} style={{ flex: 1 }} />
);

Configuration Modes

The library supports two configuration modes:

  1. Modern Configuration (Recommended)

    • Uses the unified type system (JWPlayerConfig)
    • Provides full type safety and IDE support
    • Matches JW Player Delivery API format
    • Clearly documents platform-specific features
    • Example: See TypeScript Example
  2. Legacy Configuration

    • Set forceLegacyConfig={true} in props
    • Uses older builder patterns from previous versions
    • Limited type safety and platform support
    • Not recommended for new implementations
    • Documentation: See Legacy Readme

Key Features

  • ✅ Type Safety: Full TypeScript support with autocomplete
  • ✅ Cross-Platform: Single configuration works on both iOS and Android
  • ✅ Platform Annotations: Clear documentation of platform-specific features
  • ✅ Backward Compatible: Existing configurations continue to work
  • ✅ Well Documented: Comprehensive guides for all features



Advanced Topics

Advertising | Background Audio | Casting | DRM | Metadata Events | Picture in Picture (PiP) | Styling


Advertising

Android | iOS

Android Advertising

Follow these steps to set up advertising with IMA or DAI:

  1. In the android/build.gradle ext{} block, add RNJWPlayerUseGoogleIMA = true.

    buildscript {
        ext {
            RNJWPlayerUseGoogleIMA = true
        }
    }

    This setting will add the following dependencies: com.google.ads.interactivemedia.v3:interactivemedia:3.36.0 and com.google.android.gms:play-services-ads-identifier:18.0.1.

  2. ⚠️ REQUIRED: Enable desugaring in your app (required for IMA SDK 3.37.0+):

    In your android/app/build.gradle, add the following configuration:

    android {
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
            coreLibraryDesugaringEnabled true
        }
    }
    
    dependencies {
        // ... your other dependencies
        coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
    }

Important: The IMA SDK 3.37.0+ requires desugaring due to its transitive dependencies. While the jwplayer-react-native library configures desugaring internally, Android requires that your consuming app also explicitly enable desugaring. If you skip step 2, you will get build errors like "Dependency requires core library desugaring to be enabled". This is an Android Gradle requirement where both the library and the consuming app must opt-in to desugaring.


iOS Advertising

Follow this step to set up advertising with IMA or DAI:

  1. In the Podfile ext{}, add $RNJWPlayerUseGoogleIMA = true. This setting will add GoogleAds-IMA-iOS-SDK to the pod.

Using a Local iOS SDK

To test with a specific version of JWPlayerKit (e.g. a pre-release build provided by JW Player support):

  1. Acquire the JWPlayerKit.xcframework asset.
  2. Copy it to ios/frameworks/JWPlayerKit.xcframework in this repo (this path is gitignored).
  3. Add $RNJWPlayerUseLocalSDK = true to your Podfile.
  4. Run pod install.

To switch back to the published CocoaPod, remove or comment out the $RNJWPlayerUseLocalSDK line and run pod install again.

Using Local Android AARs

To test with a specific version of the JW Player Android SDK (e.g. a pre-release build provided by JW Player support):

  1. Acquire the AAR files and copy them to android/libs/ in this repo (this path is gitignored):
    • jwplayer-core.aar, jwplayer-common.aar, jwplayer-chromecast.aar
    • jwplayer-ima.aar (if using IMA)
  2. Set useLocalAARs = true in android/build.gradle.
  3. Rebuild the app.

To switch back to Maven, set useLocalAARs = false and rebuild.



Background Audio

Background Audio allows your viewers to play audio while they are no longer actively using your app or have locked their device.

Follow these steps to enable background audio sessions:

  1. Set backgroundAudioEnabled to true in the config.
  2. Ensure that background audio is set for Android or iOS.
  3. Android 13 (API 33) and later: declare android.permission.POST_NOTIFICATIONS in your app's manifest and request it at runtime (for example with PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS)). Without it, background playback still works, but the media notification and lock-screen controls are not shown. This library already declares FOREGROUND_SERVICE and FOREGROUND_SERVICE_MEDIA_PLAYBACK for you. If background audio does not start, check logcat: the SDK's MediaService logs an error naming any missing permission.

On Android, the media notification and lock-screen controls update automatically when you call setPlaylistItemMetadata. The refreshNotification option of setPlaylistItemMetadata is deprecated: it is no longer needed, is ignored, and is slated for removal.

Android: Custom Notification Buttons

Add your own buttons (for example Like or Bookmark) to the background-audio notification and lock-screen controls with notificationButtons. Each button needs an id, a title, and an icon: the name of a drawable resource in your Android app (for example ic_like for android/app/src/main/res/drawable/ic_like.xml). Taps arrive on onNotificationButtonClick with the button's id. Change the buttons at any time, for example to show a "liked" state, with setNotificationButtons; pass [] to remove them. Omitting notificationButtons from a later config keeps the current buttons; to clear them, pass [] (in the config or to setNotificationButtons).

The buttons belong to the background-audio service, which is shared by every player in the app: they apply to the first player that starts the service, and other players share that service (and its buttons) rather than adding their own.

const [liked, setLiked] = useState(false);

const buttons = liked => [
  { id: 'like', icon: 'ic_like', title: liked ? 'Unlike' : 'Like', inCompactView: true },
  { id: 'bookmark', icon: 'ic_bookmark', title: 'Bookmark' },
];

<JWPlayer
  ref={playerRef}
  config={{ ...config, backgroundAudioEnabled: true, notificationButtons: buttons(false) }}
  onNotificationButtonClick={({ nativeEvent }) => {
    if (nativeEvent.id === 'like') {
      const next = !liked;
      setLiked(next);
      playerRef.current.setNotificationButtons(buttons(next));
    }
  }}
/>

Optional per button: enabled (default true; a disabled button keeps its place but does nothing when tapped), inCompactView (show in the collapsed notification, Android 12 and below) and placement ("overflow", "back" or "forward", a hint for the system media controls). The system decides how many buttons it shows, usually 3 to 5 including play/pause: put the important ones first. Android 13 and later hide disabled buttons and ignore inCompactView. Buttons whose icon cannot be found are skipped with a logcat warning. Keep the config object stable between renders (for example with useMemo); change buttons with setNotificationButtons rather than by rebuilding the config, and call it only when the buttons change (memoize the array with useMemo if you build it during render).

Taps (and onAudioFocusChange events) are delivered to JavaScript straight away, including while the app is in the background, so the notification can be updated before the user returns to the app.

JWPlayer calls the handler prop that is current when an event fires, so a handler that closes over state (like liked above) sees the latest render. One limitation: JWPlayer only re-renders when config or controls change, so an event handler prop added after mount (one that was undefined on earlier renders) is not registered until the next such re-render. Pass the handler from the first render, or make it a no-op until you need it.

This is Android-only; on iOS these options are ignored.

Android: Audio Focus

By default this library handles audio focus itself when backgroundAudioEnabled is true, as in earlier versions. Set audioFocusHandling: "sdk" to let the JW Android SDK manage it instead: it requests focus whenever content or an ad plays (with or without background audio), pauses when another app takes focus permanently, pauses and resumes for short interruptions such as a voice assistant prompt or a call, and lets the system lower the volume for navigation prompts (below Android 8.0 the SDK pauses and resumes for those instead). Omitting audioFocusHandling from a later config switches back to the default handling. Focus changes are reported on onAudioFocusChange (gained, lost, lostTransient, duck). The two modes never run together.

<JWPlayer
  config={{ ...config, audioFocusHandling: 'sdk' }}
  onAudioFocusChange={({ nativeEvent }) => console.log('focus', nativeEvent.change)}
/>

Independent of this setting, the Android player always pauses when headphones or a Bluetooth audio device disconnect.

Pause Reasons

onPause reports why playback paused in nativeEvent.reason: interaction, external, clickthrough, viewable, settingsInteraction, related-interaction, autostart, audio-interruption or unknown. audio-interruption is Android-only (headphones or Bluetooth disconnected, or another app took audio focus with audioFocusHandling: "sdk"); iOS reports those pauses as external or unknown.

Android Opt-Out Information

If you do not use background audio on Android, remove the background-audio permissions and service from your app. Google can and will reject your Play Store submission if an app declares the foreground-service media-playback permission without using it.

Since JW Android SDK 4.28.0 (this library's Android dependency), the MediaService is declared by both this library's manifest and the SDK's own manifest, so editing this library's manifest is not enough. Remove them in your app's AndroidManifest.xml with tools:node="remove":

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" tools:node="remove" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" tools:node="remove" />

    <application>
        <service android:name="com.jwplayer.pub.api.background.MediaService" tools:node="remove" />
    </application>
</manifest>

After doing this, do not set backgroundAudioEnabled to true on Android: the player cannot bind the removed service, so background playback and its notification will not work (the SDK logs a "Could not bind ... MediaService" warning).



Casting

Android | iOS | DRM Casting

JWX enables casting by default with a casting button.


Android Casting

Follow these steps to enable casting:

  1. In app/build.gradle in ext{}, add RNJWPlayerUseGoogleCast = true.

  2. In app/build.gradle, add com.google.android.gms:play-services-cast-framework:21.3.0.

  3. Create a class that overrides OptionsProvider in your Android codebase:

    1. See the reference file android/src/main/java/com/appgoalz/rnjwplayer/CastOptionsProvider.java.
    2. Replace .setTargetActivityClassName(RNJWPlayerView.class.getName()) with your player Activity.
    3. Modify the file with any options necessary for your use case.
  4. Add the meta-data to your AndroidManifest.xml.

     <meta-data
         android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
         android:value="path.to.CastOptionsProvider" />

iOS Casting

Follow these steps to enable casting:

  1. Enable casting to Chromecast devices.
  2. Add $RNJWPlayerUseGoogleCast = true to your Podfile. This setting will install google-cast-sdk pod.
  3. Edit Info.plist with the following values.
'NSBluetoothAlwaysUsageDescription' => 'We will use your Bluetooth for media casting.',
'NSBluetoothPeripheralUsageDescription' => 'We will use your Bluetooth for media casting.',
'NSLocalNetworkUsageDescription' => 'We will use the local network to discover Cast-enabled devices on your WiFi network.',
'Privacy - Local Network Usage Description' => 'We will use the local network to discover Cast-enabled devices on your WiFi network.'
'NSMicrophoneUsageDescription' => 'We will use your Microphone for media casting.'

Available Method Description
castState(GCKCastState) Gets the cast state
See: GCKCastState
GCKCastState
typedef NS_ENUM(NSUInteger, GCKCastState) {
  /** No Cast session is established, and no Cast devices are available. */
  GCKCastStateNoDevicesAvailable = 0,
  /** No Cast session is establishd, and Cast devices are available. */
  GCKCastStateNotConnected = 1,
  /** A Cast session is being established. */
  GCKCastStateConnecting = 2,
  /** A Cast session is established. */
  GCKCastStateConnected = 3,
};

DRM Casting

Casting your DRM protected content requires some additional configuration and most likely a custom Chromecast Receiver.

See our Android and iOS documentation about creating (iOS / Android) and sending data (iOS / Android) for more information.

To send custom data to your receiver, use the userInfo prop and avoid using the reserved sources key, as the JWX SDK will append the DRM source information here for you to parse in your DRM enabled receiver.



DRM

Enable digital rights management (DRM) protected playback.

💡 Check out the DRMExample in the Example app. The DRMExample cannot be run in the Simulator. Additionally, the window will not show on an Android Emulator.


Android DRM

Only Widevine is supported.

Follow these steps to enable DRM:

  1. Set up your Android app for DRM playback.
  2. Define config.playlist with the JWX signed URL of the media to play in the player.

❗️DO NOT sign and store your API secerets from your application.❗️

If you use a different provider for DRM or this does not work for your use case, conforming to a similiar format as a JWX signed URL response is optimal, such as adding the drm field to the sources for a playlist item).


iOS DRM

Only Fairplay is supported.

The below is currently not fully supported by the iOS SDK, so please refer to Example app, or the legacy DRM documentation. For now, you must still provide the DRM asset in the config.playlist as a legacy object [{fairplayCertUrl: string,processSpcUrl: string,file: string}]

Follow these steps to enable DRM:

  1. Set up your iOS app for DRM playback.
  2. Define config.playlist with the JWX signed URL of the media to play in the player.

❗️DO NOT sign and store your API secerets from your application.❗️

If you use a different provider for DRM or this does not work for your use case, conforming to a similiar format as a JWX signed URL response is optimal, such as adding the drm field to the sources for a playlist item).



Picture in Picture (PiP)

Android | iOS

Android PiP

  1. Read and understand the requirements for PiP in the Android SDK.
  2. In the activity where the player is embedded, add the following code.
    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
     super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
    
     Intent intent = new Intent("onPictureInPictureModeChanged");
     intent.putExtra("isInPictureInPictureMode", isInPictureInPictureMode);
     intent.putExtra("newConfig", newConfig);
     this.sendBroadcast(intent);
    }

iOS PiP

  1. Read and understand the requirements for PiP in the iOS SDK. PiP mode is enabled by JWX for the PlayerViewController.
  2. (viewOnly:true only) Set the pipEnabled prop to true.
  3. (viewOnly:true only) Call togglePIP() to enable or disable PiP.
  4. Ensure category and/or categoryOptions prop(s) are set to define and configure your media. This is required to setup the audio session. If category is not defined but pipEnabled is set true, we default to the standard playback category to avoid crashing.



Styling

Android | iOS

Android Styling

The styling prop will not work with Android when using the modern configuration system. Android styling should be handled through XML resource overrides (see below).

Android styling is best handled through overring JWX IDs in your apps resources files. See the documentation here.

A sample of overring a color via XML can be seen in this colors file. The color specified here is the default, but if you wish to change it, the color will be updated on the player.


iOS Styling

You can use the styling elements as defined in the Legacy Readme.



Metadata Events

Timed metadata embedded in the stream (ID3, EXT-X-DATERANGE including SCTE-35 markers, EXT-X-PROGRAM-DATE-TIME, DASH emsg), cue points you configure with externalMetadata, and media / access-log information are surfaced through two callbacks that mirror the web player's meta and metadataCueParsed events. Both deliver the same { metadataType, metadataTime?, metadata?, ... } payload, so one handler type covers every kind of metadata:

<JWPlayer
  config={config}
  onMetadataCueParsed={({nativeEvent}) => {
    // Fired when a cue is parsed, ahead of playback reaching it.
    console.log('parsed', nativeEvent.metadataType, nativeEvent.metadataTime);
  }}
  onMeta={({nativeEvent}) => {
    // Fired when playback enters the cue (or media / access-log info arrives).
    switch (nativeEvent.metadataType) {
      case 'id3':
        console.log(nativeEvent.metadata.title ?? nativeEvent.metadata);
        break;
      case 'date-range':
        console.log(nativeEvent.metadata.attributes);
        break;
      case 'program-date-time':
        console.log(nativeEvent.programDateTime);
        break;
    }
  }}
/>

See Metadata Events for the full payload reference and per-platform coverage, and the Metadata Events screen in the Example app for a live demo against public test streams.



Contributions

We welcome thoughtful contributions. To avoid duplicate work, review the following before opening a pull request (PR):

  • Ensure your contribution applies directly to an open issue.
  • When appropriate, develop solutions that can be applied to multiple use cases and implementations.
  • Submit small, well-scoped pull requests.

Follow these steps to contribute:

  1. Review an issue.
  2. Create a pull request to propose a solution.



Issues

To ensure issues are efficiently addressed, we outline our expectations, define what we support, and explain how to submit issues below.

Expectations

If you’re filing an issue, follow the Try → Wait → Fork model:

  • Try first. Investigate the bug. If you find the cause, submit a fix. We focus on issues backed by effort.
  • Wait patiently. We prioritize our core Native SDK development over this React-Native repository. Responses here may be delayed.
  • Fork when needed. For one-off use cases, fork the repo. We only support changes with broad value.

What We Support

We focus on work that delivers the greatest long-term value to the broader community. The following categories are listed in order of priority:

  1. Breakages and critical bugs caused by updates to the Native SDKs.
  2. Critical bugs in the wrapper that can be reproduced in the Example app.
  3. Structural issues that impact long-term maintainability.
  4. New features that align with official SDK capabilities and benefit the broader community. Note: These are prioritized lower than bugs and will be addressed only as time allows.

Issue Submissions

Follow these steps to submit an issue:

  1. Submit a bug report, feature request, implementation request, or question in this project. Note: All information requested in the submission template must be provided. If any item is not applicable, enter "N/A".
  2. (Optional) Submit a JWP support request when you need to share sensitive information.

About

No description, website, or topics provided.

Resources

Code of conduct

Stars

45 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages