npm package: @readyio/react-native-wallet
Description: React native ready wallet sdk for integrate with react native app
Author: thinhnn
Latest version: 0.1.94

# @readyio/react-native-wallet

React native ready wallet sdk for integrate with react native apps

## Installation

```sh
npm install @readyio/react-native-wallet
```
OR
```sh
yarn add @readyio/react-native-wallet
```

## Peer dependencies

```json
{
  "peerDependencies": {
    "@gorhom/bottom-sheet": "^4",
    "@nozbe/watermelondb": "^0.27.1",
    "@react-native-async-storage/async-storage": "^1.17.10",
    "@react-native-camera-roll/camera-roll": "5.2.0",
    "@react-native-clipboard/clipboard": "^1.13.1",
    "@react-native-community/blur": "^3.6.0",
    "@react-native-community/checkbox": "^0.5.16",
    "@react-native-community/datetimepicker": "^7.6.4",
    "@react-native-community/netinfo": "6.0.0",
    "@react-native-masked-view/masked-view": "^0.3.1",
    "@react-native-firebase/analytics": "^20.1.0",
    "@react-native-firebase/app": "^20.1.0",
    "@react-navigation/bottom-tabs": "^6.5.12",
    "@react-navigation/material-top-tabs": "^6.6.10",
    "@react-navigation/native": "^6.1.7",
    "@react-navigation/native-stack": "6.9.13",
    "@readyio/ready-native": "1.0.0",
    "@sentry/react-native": "^5.33.0",
    "@walletconnect/react-native-compat": "^2.11.0",
    "@walletconnect/web3wallet": "^1.10.0",
    "apisauce": "^1.1.1",
    "deprecated-react-native-prop-types": "^4.1.0",
    "i18n-js": "3.8.0",
    "lodash": "^4.17.21",
    "lottie-react-native": "^7.3.4",
    "mobx": "6.10.2",
    "mobx-react-lite": "4.0.5",
    "mobx-state-tree": "5.3.0",
    "moment": "^2.24.0",
    "react": "*",
    "react-native": "*",
    "react-native-biometrics": "^3.0.1",
    "react-native-camera": "^3.18.0",
    "react-native-collapsible-tab-view": "^8.0.0",
    "react-native-countdown-circle-timer": "^3.2.1",
    "react-native-get-random-values": "^1.10.0",
    "react-native-device-info": "^5.5.3",
    "react-native-event-listeners": "^1.0.7",
    "react-native-fast-image": "^8.6.3",
    "react-native-fast-pbkdf2": "^0.3.1",
    "react-native-fs": "^2.16.6",
    "react-native-gesture-handler": "~2.12.0",
    "react-native-hash": "^3.0.3",
    "react-native-image-picker": "^5.6.1",
    "react-native-keychain": "~8.1.2",
    "react-native-linear-gradient": "^2.8.3",
    "react-native-modal": "^13.0.1",
    "react-native-pager-view": "7.0.0-rc.0",
    "react-native-permissions": "^2.1.3",
    "react-native-pie-chart": "^3.0.2",
    "react-native-qr-decode-image-camera": "^1.1.3",
    "react-native-qrcode-scanner": "^1.5.5",
    "react-native-qrcode-svg": "^6.0.3",
    "react-native-reanimated": "3.5.4",
    "react-native-rsa-native": "^2.0.5",
    "react-native-safe-area-context": "^4.7.1",
    "react-native-screens": "3.25.0",
    "react-native-share": "^7.6.6",
    "react-native-skeleton-placeholder": "^5.2.4",
    "react-native-svg": "^13.14.0",
    "react-native-tab-view": "^3.5.2",
    "react-native-toast-message": "^2.2.0",
    "react-native-randombytes": "^3.6.1",
    "react-native-uuid": "1.4.9",
    "react-native-view-shot": "^3.8.0",
    "react-native-webview": "^13.8.1",
    "react-native-gzip": "^1.1.0"
  },
}
```

## IOS


1. Setting up Deeplink for connecting to Dapps by WalletConnect and TonConnect
    
    **Step 1**: Configuration `Linking`

    - If **`Linking`** is not installed in your React Native project, consult the [documentation](https://reactnative.dev/docs/linking); otherwise, no additional configuration is required.

    **Step 2**: Here is the command line to add data scheme in `Info.plist` in **iOS**
    ```sh
    npx uri-scheme add readywallet --ios && npx uri-scheme add tc --ios
    ```

2. WatermelonDB dependency

    ```pod
    use_modular_headers!
    
    ....
    
    #comment this line 
    # :flipper_configuration => flipper_config,
    
    ....
    
    pod 'simdjson', path: '../node_modules/@nozbe/simdjson'
    ```

3. `react-native-permissions@2.1.3`

    The Ready Wallet SDK requires access to the camera, photo and Face-ID on iOS. So, let's set up the pod file by following [this documentation](https://github.com/zoontek/react-native-permissions/tree/2.1.3)

    **Podfile**

    ```pod
    permissions_path = '../node_modules/react-native-permissions/ios'
    pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
    pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID.podspec"
    ```
    **Info.plist**                            

    ```
    <key>NSCameraUsageDescription</key>
      <string>Our app uses the camera to scan crypto wallet or account QR code and capture photos for sharing in chat or used as avatar</string>
    <key>NSFaceIDUsageDescription</key>
      <string>Authentication</string>
    <key>NSPhotoLibraryUsageDescription</key>
      <string>Access to the photo library is used for media sharing in chat or setting profile picture</string>
    ```

4. Run IOS
    ```sh
    cd ios && pod install
    yarn ios
    ```

## Android


1. Add in `android/build.gradle`

    ```jsx
    buildscript{
      ...
      kotlinVersion = '1.7.20'
      minSdkVersion = 23
      ...
    }

    dependencies {
      ...
      classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
    }
    ```

2. Add this code to android/app/build.gradle

    ```jsx
    defaultConfig {
      ...
      missingDimensionStrategy 'react-native-camera', 'general'
    }

    ...
    configurations {
        all*.exclude module: 'bcprov-jdk15to18'
    }


    dependencies {
      ...
      implementation project(':react-native-fs')
      implementation 'me.leolin:ShortcutBadger:1.1.21@aar'
      implementation project(':react-native-camera')
      implementation('org.bitcoinj:bitcoinj-core:0.16.1') {
          exclude group: 'net.jcip', module: 'jcip-annotations'
      }
      implementation 'org.whispersystems:curve25519-android:0.2.5'
      implementation ('org.web3j:core:4.8.7-android')
      ...
    }
    ```

3. Require permissions on  **AndroidManifest.xml**

    ```
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.CAMERA" />
    ```

4. Deeplink for connecting to Dapps by WalletConnect and TonConnect

    ```jsx
    npx uri-scheme add readywallet --android && npx uri-scheme add wc --android && npx uri-scheme add tc --android
    ```
5. Add the following code to AndroidManifest.xml in Android

    ```
    <activity
      android:name="com.readyio.readywallet.ReadyWalletActivity"
      android:windowSoftInputMode="adjustResize"
      android:taskAffinity="com.readyio.readywallet.miniapp"
      android:launchMode="singleTop"
      android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
    />
    ```
6. If you encounter `error: resource android:attr/lStar not found` during release build, add the following code at the end of `android/build.gradle`
  ```
  subprojects {
    afterEvaluate { project ->
        if (project.hasProperty('android')) {
            project.android { compileSdkVersion 34 }
        }
    }
  }
  ```

## Simple Usage

```js
import ready from '@readyio/react-native-wallet';

ready.openApp({
  /* Configuration */
})
```

Available configuration:

| Key | Description | Value Type | Default | Required |
| --- | --- | --- | --- | --- |
| language | miniapp language | "en", "vi" | "vi" | NO |
| deepLinkUrl | used to forward deeplink from superapp to miniapp | string | undefined | NO |
| walletId | used to indicate which wallet a user has open | string | undefined | NO |
| userId | current userId of supper app | string | '' | YES |
| isCreateNewWallet | used to indicate the user to open the mini app to create a wallet | bool | false | NO |
| userInfo | Send supper app user infomation to miniapp  | UserInfo | false | NO |
| isOnlyReady | Act as a seperate app  | bool | false | NO |

## Get list of Wallet information from miniapp

```js
import ready, { WalletDataType, Icon3D } from '@readyio/react-native-wallet';

const data: WalletDataType[] = await ready.getReadyWallets(userId)

// render wallet icon
<Icon3D icon={data[0].icon} />
```


## Deep Linking

To handle deep links for using **WalletConnect** to connect with a **DApp** in MiniApp, here are the examples:

1. Foreground (SuperApp is open)[](https://reactnative.dev/docs/linking?syntax=ios#1-if-the-app-is-already-open-the-app-is-foregrounded-and-a-linking-url-event-is-fired)

    You can handle these events with `Linking.addEventListener('url', callback)` - it calls `callback({url})` with the linked URL

    E.g

    ```jsx
    import ready from '@readyio/react-native-wallet';

    useEffect(() => {
      const handleUrl = (event) => {
        const url = event.url;

        // Forward deeplink to Ready
        if (url.startsWith('wc:') || url.startsWith('tc:') || url.startsWith('readywallet:')) {
          ready.openApp({ deepLinkUrl: url, userId: "userId" })
        }
      };

      Linking.addEventListener('url', handleUrl);

      return () => {
        Linking.removeEventListener('url', handleUrl);
      };
    }, []);
    ```

2. Background (SuperApp is running in the background)[](https://reactnative.dev/docs/linking?syntax=ios#2-if-the-app-is-not-already-open-it-is-opened-and-the-url-is-passed-in-as-the-initialurl)

    ```jsx
    import ready from '@readyio/react-native-wallet';

    useEffect(() => {
      const handleUrl = async (url) => {
        // Forward deeplink to Ready
        if (url.startsWith('wc:') || url.startsWith('tc:') || url.startsWith('readywallet:')) {
          ready.openApp({ deepLinkUrl: url, userId: "userId" })
        }
      };

      const getUrlAsync = async () => {
        const initialUrl = await Linking.getInitialURL();
        if (initialUrl) {
          handleUrl(initialUrl);
        }
      };

      const handleAppStateChange = (nextAppState) => {
        if (nextAppState === 'active') {
          getUrlAsync();
        }
      };

      AppState.addEventListener('change', handleAppStateChange);

      return () => {
        AppState.removeEventListener('change', handleAppStateChange);
      };
    }, []);
    ```

3. App is completely closed

    ```jsx
    import ready from '@readyio/react-native-wallet';

    useEffect(() => {
      const getUrlAsync = async () => {
        const url = await Linking.getInitialURL();
        if (url) {
          // Forward deeplink to Ready
          if (url.startsWith('wc:') || url.startsWith('tc:') || url.startsWith('readywallet:')) {
            ready.openApp({ deepLinkUrl: url, userId: "userId" })
          }
        }
      };

      getUrlAsync();
    }, []);
    ```

## Push Notification

### Register for Firebase Cloud Messaging with Ready

Please contact Ready team to set up push notification key on server side

### Config in client

#### An example of setting up ready push notification using `@react-native-firebase/messaging`

1. Setup device token
    ```js
      import ready from '@readyio/react-native-wallet';
      import messaging from '@react-native-firebase/messaging'

      // Setup FCM token
      messaging().getToken().then((token) => {
        ready.setDeviceToken(token)
        // Do logic here
      })

    ```

2. Setup handler

    ```js
      import ready from '@readyio/react-native-wallet';
      import messaging from '@react-native-firebase/messaging'

      // Forground handler
      messaging().onMessage((message: FirebaseMessagingTypes.RemoteMessage) => {
        if (ready.isReadyPush(message.data)) return

        // Handle non-ready message
      })

      // Background handler
      messaging().setBackgroundMessageHandler(async (message: FirebaseMessagingTypes.RemoteMessage) => {
        if (ready.isReadyPush(message.data)) return

        // Handle non-ready message
      })

    ```

#### An example of setting up ready push notification using `react-native-onesignal`

1. Init appid and add listener event
    ```js
      import { LogLevel, OneSignal } from 'react-native-onesignal'

      useEffect(() => {
        // Remove this method to stop OneSignal Debugging
        OneSignal.Debug.setLogLevel(LogLevel.Verbose)

        // OneSignal Initialization
        OneSignal.initialize('OneSignal App ID')

        OneSignal.login('externalId')
        // requestPermission will show the native iOS or Android notification permission prompt.
        // We recommend removing the following code and instead using an In-App Message to prompt for notification permission
        OneSignal.Notifications.requestPermission(true)

        // Method for listening for notification clicks
        OneSignal.Notifications.addEventListener('click', (event) => {
          if (ready.isReadyPush(event.notification.additionalData)) {
            console.log('Ready Push:  clicked:', event.notification.additionalData)
            return
          }
             // Handle non-ready event
        })

        OneSignal.Notifications.addEventListener('foregroundWillDisplay', (event) => {
          if (ready.isReadyPush(event.notification.additionalData)) {
            console.log('Ready Push:  foregroundWillDisplay:', event.notification.additionalData)
            return
          }
         // Handle non-ready event
        })
      }, [])
    ```        

## Android 14 support (SDK34)

MainApplication.java
```java
// Add imports
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import org.jetbrains.annotations.Nullable;

// ...

// Put this above  "public void onCreate()":
  @Override
  public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
    if (Build.VERSION.SDK_INT >= 34 && getApplicationInfo().targetSdkVersion >= 34) {
      return super.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED);
    } else {
      return super.registerReceiver(receiver, filter);
    }
  }
// ....
```
app/build.gradle
```
dependencies {
     //  ...
    implementation 'org.jetbrains:annotations:16.0.2'
    // ...
}
```

## Supported Versions

The library version is stable and works without issues when using React Native version 0.71.8. If you encounter any errors during the installation process, please contact the Ready Team for support.

## Contributing

See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.

## License

MIT