Skip to content

Add expo-plugin setup#17

Merged
predatorx7 merged 10 commits intomainfrom
mushaheed.expo_setup
Jun 27, 2025
Merged

Add expo-plugin setup#17
predatorx7 merged 10 commits intomainfrom
mushaheed.expo_setup

Conversation

@predatorx7
Copy link
Collaborator

@predatorx7 predatorx7 commented Jun 25, 2025

Summary by CodeRabbit

  • New Features

    • Added support for Expo Android through new configuration plugins modifying AndroidManifest and build.gradle files.
    • Introduced a comprehensive example Expo app showcasing SDK integration with full Android and iOS native setup.
    • Included React Native components and hooks for theming, navigation, verification flows, and UI enhancements in the example app.
  • Chores

    • Updated package version and enhanced build scripts to compile and package the Expo plugin.
    • Added TypeScript configurations for the Expo plugin and example project.
    • Removed internal CI workflows and setup actions to simplify repository maintenance.
  • Documentation

    • Added detailed Expo-specific installation and setup instructions along with example project documentation.
    • Updated changelog to reflect Expo Android support and new release version.

@coderabbitai
Copy link

coderabbitai bot commented Jun 25, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces an Expo config plugin version 0.9.4-alpha.4 adding support for Expo Android integration. It includes new TypeScript source files for Android manifest and Gradle modifications, configuration files, build scripts, and example project setup. It updates package metadata, TypeScript settings, and documentation. The GitHub Actions CI workflow and setup action were removed.

Changes

File(s) Change Summary
expo-plugin/src/index.ts, expo-plugin/src/android/index.ts,
expo-plugin/src/android/withReclaimAndroidManifest.ts, expo-plugin/src/android/withReclaimProjectBuildGradle.ts
Added new Expo config plugin for Android with manifest and Gradle build modifications.
expo-plugin/tsconfig.json Added TypeScript configuration for Expo plugin source directory.
app.plugin.js Added proxy export file forwarding to built Expo plugin module.
package.json Updated version to 0.9.4-alpha.4, added build and prepack scripts, included expo-plugin directory and app.plugin.js in files and exports, added devDependency.
CHANGELOG.md Added version 0.9.4-alpha.4 entry noting Expo Android support.
.github/workflows/ci.yml, .github/actions/setup/action.yml Deleted GitHub Actions CI workflow and custom setup action.
tsconfig.json, tsconfig.build.json Updated TypeScript include/exclude patterns and expanded build exclusions.
README.md Added Expo-specific setup instructions and installation guidance.
samples/example_expo/** Added a complete new Expo example project with source code, Android and iOS native projects, configuration files, assets, scripts, and documentation.
samples/example_expo/app/(home)/_layout.tsx, samples/example_expo/app/+not-found.tsx, samples/example_expo/app/_layout.tsx Added new React Native Expo app screens and root layout with theming and navigation.
samples/example_expo/components/** Added multiple new UI components including Collapsible, ExternalLink, HapticTab, HelloWave, ParallaxScrollView, ThemedText, ThemedView, and cross-platform IconSymbol components.
samples/example_expo/constants/Colors.ts Added color palette definitions for light and dark themes.
samples/example_expo/hooks/** Added hooks for color scheme detection and theme color resolution.
samples/example_expo/ios/** Added full iOS native project files including Podfile, Xcode project, AppDelegate, Info.plist, assets, and supporting files.
samples/example_expo/android/** Added full Android native project files including Gradle build scripts, manifests, Kotlin source files, resources, and configuration.
samples/example_expo/scripts/reset-project.js Added script to reset project structure by moving or deleting existing app folders and creating blank app.
samples/example_expo/package.json Added package.json for the example Expo project with dependencies and scripts.
samples/example_expo/tsconfig.json Added TypeScript configuration extending Expo base with strict mode and path aliases.
user-workspace/src/App.tsx Added explicit React import.

Sequence Diagram(s)

sequenceDiagram
    participant AppConfig
    participant withReclaimInAppSdk
    participant withReclaimAndroidManifest
    participant withReclaimProjectBuildGradle

    AppConfig->>withReclaimInAppSdk: Apply plugin
    withReclaimInAppSdk->>withReclaimAndroidManifest: Modify AndroidManifest.xml
    withReclaimInAppSdk->>withReclaimProjectBuildGradle: Modify project build.gradle
    withReclaimAndroidManifest-->>withReclaimInAppSdk: Return updated config
    withReclaimProjectBuildGradle-->>withReclaimInAppSdk: Return updated config
    withReclaimInAppSdk-->>AppConfig: Return fully updated config
Loading

Possibly related PRs

Suggested labels

documentation

Suggested reviewers

  • kryptocodes

Poem

🐇 Hop, hop, a plugin new,
Expo Android joins the crew!
Manifest tweaks, Gradle too,
Example apps fresh and true.
CI hops off, docs now bright,
Build scripts hum with pure delight.
Version 0.9.4-alpha.4 takes flight! 🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fad1b1 and cb8f904.

📒 Files selected for processing (1)
  • samples/example_expo/README.md (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
expo-plugin/src/index.ts (1)

1-14: Fix formatting issues flagged by Prettier.

The plugin logic is correct and follows Expo plugin patterns well. However, there are several formatting issues that need to be addressed.

Apply this diff to fix the formatting issues:

-import { type ConfigPlugin, withPlugins } from '@expo/config-plugins';
-import {
-    installReclaimAndroidManifest,
-    installReclaimProjectBuildGradle,
-} from './android';
+import { type ConfigPlugin, withPlugins } from '@expo/config-plugins';
+import {
+  installReclaimAndroidManifest,
+  installReclaimProjectBuildGradle,
+} from './android';

 const withReclaimInAppSdk: ConfigPlugin = (config) => {
-    return withPlugins(config, [
-        installReclaimAndroidManifest,
-        installReclaimProjectBuildGradle,
-    ]);
+  return withPlugins(config, [
+    installReclaimAndroidManifest,
+    installReclaimProjectBuildGradle,
+  ]);
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0bc114 and df37d0a.

📒 Files selected for processing (8)
  • CHANGELOG.md (1 hunks)
  • app.plugin.js (1 hunks)
  • expo-plugin/src/android/index.ts (1 hunks)
  • expo-plugin/src/android/install_reclaim_android_manifest.ts (1 hunks)
  • expo-plugin/src/android/install_reclaim_project_build_gradle.ts (1 hunks)
  • expo-plugin/src/index.ts (1 hunks)
  • expo-plugin/tsconfig.json (1 hunks)
  • package.json (4 hunks)
🧰 Additional context used
🪛 ESLint
expo-plugin/src/index.ts

[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Replace ········ with ····

(prettier/prettier)


[error] 10-10: Replace ········ with ····

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)

expo-plugin/src/android/install_reclaim_project_build_gradle.ts

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Replace ····const·flutterStorageUrl·=·process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||·config.android['FLUTTER_STORAGE_BASE_URL']·||·"https://storage.googleapis.com" with const·flutterStorageUrl·=⏎······process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||⏎······config.android['FLUTTER_STORAGE_BASE_URL']·||⏎······'https://storage.googleapis.com';

(prettier/prettier)


[error] 9-9: Replace ····const·reclaimStorageUrl·=·process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||·config.android['RECLAIM_STORAGE_BASE_URL']·||·"https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo" with const·reclaimStorageUrl·=⏎······process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||⏎······config.android['RECLAIM_STORAGE_BASE_URL']·||⏎······'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';

(prettier/prettier)


[error] 11-11: Delete ····

(prettier/prettier)


[error] 12-12: Replace ············ with ······

(prettier/prettier)


[error] 13-13: Delete ········

(prettier/prettier)


[error] 14-14: Delete ········

(prettier/prettier)


[error] 18-18: Delete ······

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Insert

(prettier/prettier)

expo-plugin/src/android/install_reclaim_android_manifest.ts

[error] 4-4: Delete ··

(prettier/prettier)


[error] 5-5: Delete ····

(prettier/prettier)


[error] 6-6: Delete ····

(prettier/prettier)


[error] 8-8: Replace ········ with ····

(prettier/prettier)


[error] 9-9: Delete ······

(prettier/prettier)


[error] 10-10: Replace ········ with ····

(prettier/prettier)


[error] 12-13: Delete ⏎····

(prettier/prettier)


[error] 15-15: Delete ····

(prettier/prettier)


[error] 16-16: Replace ········ with ····

(prettier/prettier)


[error] 17-17: Delete ····

(prettier/prettier)


[error] 18-18: Replace ········ with ····

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 22-22: Delete ····

(prettier/prettier)


[error] 23-23: Replace ············ with ······

(prettier/prettier)


[error] 24-24: Delete ····

(prettier/prettier)


[error] 26-26: Replace ········ with ····

(prettier/prettier)


[error] 27-27: Delete ······

(prettier/prettier)


[error] 28-29: Replace ················act.$['android:name']·!=⏎··············· with ········act.$['android:name']·!=

(prettier/prettier)


[error] 30-30: Replace ········ with ····

(prettier/prettier)


[error] 32-32: Delete ····

(prettier/prettier)


[error] 33-33: Replace ············ with ······

(prettier/prettier)


[error] 34-34: Delete ········

(prettier/prettier)


[error] 35-35: Replace ················ with ········

(prettier/prettier)


[error] 36-36: Replace ················'android:configChanges': with ········'android:configChanges':⏎·········

(prettier/prettier)


[error] 37-37: Delete ········

(prettier/prettier)


[error] 38-38: Replace ················ with ········

(prettier/prettier)


[error] 39-39: Delete ······

(prettier/prettier)


[error] 40-40: Delete ····

(prettier/prettier)


[error] 42-42: Delete ····

(prettier/prettier)


[error] 43-43: Delete ··

(prettier/prettier)


[error] 44-44: Insert

(prettier/prettier)

🔇 Additional comments (8)
expo-plugin/tsconfig.json (1)

1-11: LGTM! Standard TypeScript configuration for Expo plugin.

The configuration is well-structured with appropriate compiler options for building a plugin that generates declaration files and outputs to a build directory.

CHANGELOG.md (1)

1-4: LGTM! Clear changelog entry for the new Expo Android support.

The entry properly documents the new feature addition with appropriate version numbering.

app.plugin.js (1)

1-1: LGTM! Standard Expo plugin entry point pattern.

This follows the common practice of re-exporting the built plugin for easy consumption by Expo projects.

expo-plugin/src/android/index.ts (1)

1-2: LGTM! Clean export pattern for Android plugins.

The named exports provide a clear interface for the Android-specific plugin functionality.

package.json (4)

3-3: LGTM: Version bump is appropriate.

The version increment from 0.9.2 to 0.9.3 correctly reflects the addition of new Expo plugin functionality.


23-23: LGTM: Expo plugin directory properly included.

Adding the "expo-plugin" directory to the files array ensures the plugin code will be included in the published package.


51-53: LGTM: Build scripts properly configured.

The build scripts correctly ensure that both the main SDK and the Expo plugin are compiled during prepare and prepack phases. The TypeScript compilation for the expo-plugin directory is properly configured.


77-77: LGTM: Appropriate dependency for Expo plugin development.

The @expo/config-plugins dependency is correctly added as a devDependency, which is the standard approach for Expo plugin development.

Comment on lines 1 to 22
import {
type ConfigPlugin,
withProjectBuildGradle,
} from '@expo/config-plugins';

export const installReclaimProjectBuildGradle: ConfigPlugin = (config) => {
return withProjectBuildGradle(config, async (config) => {
const flutterStorageUrl = process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL || config.android['FLUTTER_STORAGE_BASE_URL'] || "https://storage.googleapis.com"
const reclaimStorageUrl = process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL || config.android['RECLAIM_STORAGE_BASE_URL'] || "https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo"

if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
config.modResults.contents = config.modResults.contents.replace(
/mavenCentral\(\)/g,
`
mavenCentral()
maven { url "${reclaimStorageUrl}" }
maven { url "${flutterStorageUrl}/download.flutter.io" }`
);
}
return config;
});
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix formatting issues and improve error handling.

The plugin logic is sound, but there are several formatting and potential robustness issues to address.

Apply this diff to fix formatting and improve error handling:

import {
-    type ConfigPlugin,
-    withProjectBuildGradle,
+  type ConfigPlugin,
+  withProjectBuildGradle,
} from '@expo/config-plugins';

export const installReclaimProjectBuildGradle: ConfigPlugin = (config) => {
-    return withProjectBuildGradle(config, async (config) => {
-        const flutterStorageUrl = process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL || config.android['FLUTTER_STORAGE_BASE_URL'] || "https://storage.googleapis.com"
-        const reclaimStorageUrl = process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL || config.android['RECLAIM_STORAGE_BASE_URL'] || "https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo"
+  return withProjectBuildGradle(config, async (config) => {
+    const flutterStorageUrl =
+      process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL ||
+      config.android?.['FLUTTER_STORAGE_BASE_URL'] ||
+      'https://storage.googleapis.com';
+    const reclaimStorageUrl =
+      process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL ||
+      config.android?.['RECLAIM_STORAGE_BASE_URL'] ||
+      'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';

-        if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
-            config.modResults.contents = config.modResults.contents.replace(
-                /mavenCentral\(\)/g,
-                `
-          mavenCentral()
-          maven { url "${reclaimStorageUrl}" }
-          maven { url "${flutterStorageUrl}/download.flutter.io" }`
-            );
-        }
-        return config;
-    });
+    if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
+      config.modResults.contents = config.modResults.contents.replace(
+        /mavenCentral\(\)/g,
+        `mavenCentral()
+          maven { url "${reclaimStorageUrl}" }
+          maven { url "${flutterStorageUrl}/download.flutter.io" }`
+      );
+    }
+    return config;
+  });
};

Key improvements:

  1. Fixed all formatting issues identified by Prettier
  2. Added optional chaining (?.) for safer property access
  3. Used consistent single quotes
  4. Improved template string formatting
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import {
type ConfigPlugin,
withProjectBuildGradle,
} from '@expo/config-plugins';
export const installReclaimProjectBuildGradle: ConfigPlugin = (config) => {
return withProjectBuildGradle(config, async (config) => {
const flutterStorageUrl = process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL || config.android['FLUTTER_STORAGE_BASE_URL'] || "https://storage.googleapis.com"
const reclaimStorageUrl = process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL || config.android['RECLAIM_STORAGE_BASE_URL'] || "https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo"
if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
config.modResults.contents = config.modResults.contents.replace(
/mavenCentral\(\)/g,
`
mavenCentral()
maven { url "${reclaimStorageUrl}" }
maven { url "${flutterStorageUrl}/download.flutter.io" }`
);
}
return config;
});
};
import {
type ConfigPlugin,
withProjectBuildGradle,
} from '@expo/config-plugins';
export const installReclaimProjectBuildGradle: ConfigPlugin = (config) => {
return withProjectBuildGradle(config, async (config) => {
const flutterStorageUrl =
process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL ||
config.android?.['FLUTTER_STORAGE_BASE_URL'] ||
'https://storage.googleapis.com';
const reclaimStorageUrl =
process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL ||
config.android?.['RECLAIM_STORAGE_BASE_URL'] ||
'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';
if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
config.modResults.contents = config.modResults.contents.replace(
/mavenCentral\(\)/g,
`mavenCentral()
maven { url "${reclaimStorageUrl}" }
maven { url "${flutterStorageUrl}/download.flutter.io" }`
);
}
return config;
});
};
🧰 Tools
🪛 ESLint

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Replace ····const·flutterStorageUrl·=·process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||·config.android['FLUTTER_STORAGE_BASE_URL']·||·"https://storage.googleapis.com" with const·flutterStorageUrl·=⏎······process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||⏎······config.android['FLUTTER_STORAGE_BASE_URL']·||⏎······'https://storage.googleapis.com';

(prettier/prettier)


[error] 9-9: Replace ····const·reclaimStorageUrl·=·process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||·config.android['RECLAIM_STORAGE_BASE_URL']·||·"https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo" with const·reclaimStorageUrl·=⏎······process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||⏎······config.android['RECLAIM_STORAGE_BASE_URL']·||⏎······'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';

(prettier/prettier)


[error] 11-11: Delete ····

(prettier/prettier)


[error] 12-12: Replace ············ with ······

(prettier/prettier)


[error] 13-13: Delete ········

(prettier/prettier)


[error] 14-14: Delete ········

(prettier/prettier)


[error] 18-18: Delete ······

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 22-22: Insert

(prettier/prettier)

🤖 Prompt for AI Agents
In expo-plugin/src/android/install_reclaim_project_build_gradle.ts lines 1 to
22, fix formatting issues by aligning indentation and spacing consistently,
replace double quotes with single quotes for string literals, and improve
template string formatting for readability. Add optional chaining when accessing
config.android properties to avoid runtime errors if those properties are
undefined. These changes will enhance code robustness and maintain consistent
style.

Comment on lines 1 to 44
import { type ConfigPlugin, withAndroidManifest } from '@expo/config-plugins';

export const installReclaimAndroidManifest: ConfigPlugin = (config) => {
return withAndroidManifest(config, (config) => {
let androidManifest = config.modResults.manifest;
const cannotInstallMessage = 'cannot install reclaim inapp android sdk';

if (!androidManifest) {
throw new Error(`No AndroidManifest found, ${cannotInstallMessage}`);
}


let application = androidManifest.application![0];

// Add the tools to apply permission remove
// Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
// androidManifest.$ = {
// ...androidManifest.$,
// 'xmlns:tools': 'http://schemas.android.com/tools',
// };

if (!application) {
throw new Error(`No base application found, ${cannotInstallMessage}`);
}

application.activity = application.activity!.filter(
(act) =>
act.$['android:name'] !=
'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
);

application.activity.push({
$: {
'android:name': 'org.reclaimprotocol.inapp_sdk.ReclaimActivity',
'android:theme': '@style/Theme.ReclaimInAppSdk.LaunchTheme',
'android:configChanges': 'orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode',
'android:hardwareAccelerated': 'true',
'android:windowSoftInputMode': 'adjustResize',
},
});

return config;
});
}; No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix extensive formatting issues while preserving solid logic.

The plugin logic is well-structured with proper error handling and duplicate prevention, but requires significant formatting fixes.

Apply this diff to fix all formatting issues:

import { type ConfigPlugin, withAndroidManifest } from '@expo/config-plugins';

export const installReclaimAndroidManifest: ConfigPlugin = (config) => {
-    return withAndroidManifest(config, (config) => {
-        let androidManifest = config.modResults.manifest;
-        const cannotInstallMessage = 'cannot install reclaim inapp android sdk';
+  return withAndroidManifest(config, (config) => {
+    let androidManifest = config.modResults.manifest;
+    const cannotInstallMessage = 'cannot install reclaim inapp android sdk';

-        if (!androidManifest) {
-            throw new Error(`No AndroidManifest found, ${cannotInstallMessage}`);
-        }
-
-
-        let application = androidManifest.application![0];
+    if (!androidManifest) {
+      throw new Error(`No AndroidManifest found, ${cannotInstallMessage}`);
+    }

-        // Add the tools to apply permission remove
-        // Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
-        // androidManifest.$ = {
-        //   ...androidManifest.$,
-        //   'xmlns:tools': 'http://schemas.android.com/tools',
-        // };
+    let application = androidManifest.application![0];

-        if (!application) {
-            throw new Error(`No base application found, ${cannotInstallMessage}`);
-        }
+    // Add the tools to apply permission remove
+    // Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
+    // androidManifest.$ = {
+    //   ...androidManifest.$,
+    //   'xmlns:tools': 'http://schemas.android.com/tools',
+    // };

-        application.activity = application.activity!.filter(
-            (act) =>
-                act.$['android:name'] !=
-                'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
-        );
+    if (!application) {
+      throw new Error(`No base application found, ${cannotInstallMessage}`);
+    }

-        application.activity.push({
-            $: {
-                'android:name': 'org.reclaimprotocol.inapp_sdk.ReclaimActivity',
-                'android:theme': '@style/Theme.ReclaimInAppSdk.LaunchTheme',
-                'android:configChanges': 'orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode',
-                'android:hardwareAccelerated': 'true',
-                'android:windowSoftInputMode': 'adjustResize',
-            },
-        });
+    application.activity = application.activity!.filter(
+      (act) =>
+        act.$['android:name'] != 'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
+    );

-        return config;
-    });
+    application.activity.push({
+      $: {
+        'android:name': 'org.reclaimprotocol.inapp_sdk.ReclaimActivity',
+        'android:theme': '@style/Theme.ReclaimInAppSdk.LaunchTheme',
+        'android:configChanges':
+          'orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode',
+        'android:hardwareAccelerated': 'true',
+        'android:windowSoftInputMode': 'adjustResize',
+      },
+    });
+
+    return config;
+  });
};

The core logic is excellent with proper error handling and duplicate prevention. The activity configuration appears appropriate for Android SDK integration.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { type ConfigPlugin, withAndroidManifest } from '@expo/config-plugins';
export const installReclaimAndroidManifest: ConfigPlugin = (config) => {
return withAndroidManifest(config, (config) => {
let androidManifest = config.modResults.manifest;
const cannotInstallMessage = 'cannot install reclaim inapp android sdk';
if (!androidManifest) {
throw new Error(`No AndroidManifest found, ${cannotInstallMessage}`);
}
let application = androidManifest.application![0];
// Add the tools to apply permission remove
// Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
// androidManifest.$ = {
// ...androidManifest.$,
// 'xmlns:tools': 'http://schemas.android.com/tools',
// };
if (!application) {
throw new Error(`No base application found, ${cannotInstallMessage}`);
}
application.activity = application.activity!.filter(
(act) =>
act.$['android:name'] !=
'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
);
application.activity.push({
$: {
'android:name': 'org.reclaimprotocol.inapp_sdk.ReclaimActivity',
'android:theme': '@style/Theme.ReclaimInAppSdk.LaunchTheme',
'android:configChanges': 'orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode',
'android:hardwareAccelerated': 'true',
'android:windowSoftInputMode': 'adjustResize',
},
});
return config;
});
};
import { type ConfigPlugin, withAndroidManifest } from '@expo/config-plugins';
export const installReclaimAndroidManifest: ConfigPlugin = (config) => {
return withAndroidManifest(config, (config) => {
let androidManifest = config.modResults.manifest;
const cannotInstallMessage = 'cannot install reclaim inapp android sdk';
if (!androidManifest) {
throw new Error(`No AndroidManifest found, ${cannotInstallMessage}`);
}
let application = androidManifest.application![0];
// Add the tools to apply permission remove
// Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
// androidManifest.$ = {
// ...androidManifest.$,
// 'xmlns:tools': 'http://schemas.android.com/tools',
// };
if (!application) {
throw new Error(`No base application found, ${cannotInstallMessage}`);
}
application.activity = application.activity!.filter(
(act) =>
act.$['android:name'] != 'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
);
application.activity.push({
$: {
'android:name': 'org.reclaimprotocol.inapp_sdk.ReclaimActivity',
'android:theme': '@style/Theme.ReclaimInAppSdk.LaunchTheme',
'android:configChanges':
'orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode',
'android:hardwareAccelerated': 'true',
'android:windowSoftInputMode': 'adjustResize',
},
});
return config;
});
};
🧰 Tools
🪛 ESLint

[error] 4-4: Delete ··

(prettier/prettier)


[error] 5-5: Delete ····

(prettier/prettier)


[error] 6-6: Delete ····

(prettier/prettier)


[error] 8-8: Replace ········ with ····

(prettier/prettier)


[error] 9-9: Delete ······

(prettier/prettier)


[error] 10-10: Replace ········ with ····

(prettier/prettier)


[error] 12-13: Delete ⏎····

(prettier/prettier)


[error] 15-15: Delete ····

(prettier/prettier)


[error] 16-16: Replace ········ with ····

(prettier/prettier)


[error] 17-17: Delete ····

(prettier/prettier)


[error] 18-18: Replace ········ with ····

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 22-22: Delete ····

(prettier/prettier)


[error] 23-23: Replace ············ with ······

(prettier/prettier)


[error] 24-24: Delete ····

(prettier/prettier)


[error] 26-26: Replace ········ with ····

(prettier/prettier)


[error] 27-27: Delete ······

(prettier/prettier)


[error] 28-29: Replace ················act.$['android:name']·!=⏎··············· with ········act.$['android:name']·!=

(prettier/prettier)


[error] 30-30: Replace ········ with ····

(prettier/prettier)


[error] 32-32: Delete ····

(prettier/prettier)


[error] 33-33: Replace ············ with ······

(prettier/prettier)


[error] 34-34: Delete ········

(prettier/prettier)


[error] 35-35: Replace ················ with ········

(prettier/prettier)


[error] 36-36: Replace ················'android:configChanges': with ········'android:configChanges':⏎·········

(prettier/prettier)


[error] 37-37: Delete ········

(prettier/prettier)


[error] 38-38: Replace ················ with ········

(prettier/prettier)


[error] 39-39: Delete ······

(prettier/prettier)


[error] 40-40: Delete ····

(prettier/prettier)


[error] 42-42: Delete ····

(prettier/prettier)


[error] 43-43: Delete ··

(prettier/prettier)


[error] 44-44: Insert

(prettier/prettier)

🤖 Prompt for AI Agents
In expo-plugin/src/android/install_reclaim_android_manifest.ts lines 1 to 44,
the code logic is solid but the formatting is inconsistent and needs cleanup.
Fix indentation to be uniform, remove unnecessary blank lines, and ensure
consistent spacing around operators and braces. Also, uncomment and properly
format the androidManifest.$ assignment to add the 'xmlns:tools' attribute as
intended. Preserve all existing logic and error handling while improving
readability and style.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
expo-plugin/src/index.ts (1)

7-12: Fix formatting in the plugin implementation.

The plugin logic is correct, but the formatting needs to be consistent.

Apply this diff to fix the formatting:

 const withReclaimInAppSdk: ConfigPlugin = (config) => {
-    return withPlugins(config, [
-        withReclaimAndroidManifest,
-        withReclaimProjectBuildGradle,
-    ]);
+  return withPlugins(config, [
+    withReclaimAndroidManifest,
+    withReclaimProjectBuildGradle,
+  ]);
 };
expo-plugin/src/android/withReclaimProjectBuildGradle.ts (2)

8-9: Add missing semicolons and improve variable declarations.

The variable declarations are missing semicolons, which is inconsistent with TypeScript best practices.

Apply this diff to add semicolons:

-        const flutterStorageUrl = process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL || "https://storage.googleapis.com"
-        const reclaimStorageUrl = process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL || "https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo"
+        const flutterStorageUrl =
+          process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL ||
+          'https://storage.googleapis.com';
+        const reclaimStorageUrl =
+          process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL ||
+          'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';

11-19: Consider more targeted repository injection approach.

The current implementation replaces ALL occurrences of mavenCentral() which could potentially affect unrelated repository configurations. Also, the hardcoded indentation might not match the original file's formatting.

Consider a more targeted approach that adds repositories to a specific repositories block:

-        if (!config.modResults.contents.match('reclaim-inapp-sdk')) {
-            config.modResults.contents = config.modResults.contents.replace(
-                /mavenCentral\(\)/g,
-    `
-    mavenCentral()
-    maven { url "${reclaimStorageUrl}" }
-    maven { url "${flutterStorageUrl}/download.flutter.io" }`
-            );
-        }
+        if (!config.modResults.contents.includes('reclaim-inapp-sdk')) {
+          // Find the allprojects repositories block and add our repositories
+          const repositoriesRegex = /(allprojects\s*\{[\s\S]*?repositories\s*\{[^}]*)(mavenCentral\(\))/;
+          if (repositoriesRegex.test(config.modResults.contents)) {
+            config.modResults.contents = config.modResults.contents.replace(
+              repositoriesRegex,
+              `$1$2
+        maven { url "${reclaimStorageUrl}" }
+        maven { url "${flutterStorageUrl}/download.flutter.io" }`
+            );
+          }
+        }

This approach is more targeted and preserves the original indentation style.

expo-plugin/src/android/withReclaimAndroidManifest.ts (1)

15-21: Consider removing or documenting the commented code.

The commented code block for adding tools namespace should either be removed if not needed, or properly documented if it might be used in the future.

If this code is not needed, remove it:

-        // Add the tools to apply permission remove
-        // Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
-        // androidManifest.$ = {
-        //   ...androidManifest.$,
-        //   'xmlns:tools': 'http://schemas.android.com/tools',
-        // };

Or if it's for future use, improve the documentation:

-        // Add the tools to apply permission remove
-        // Let the consumer app apply the permission on their app. All permissions are optional for this Reclaim InApp SDK.
-        // androidManifest.$ = {
-        //   ...androidManifest.$,
-        //   'xmlns:tools': 'http://schemas.android.com/tools',
-        // };
+        // TODO: Uncomment this if we need to remove permissions in the future
+        // Currently, we let the consumer app handle all permissions since they are optional
+        // androidManifest.$ = {
+        //   ...androidManifest.$,
+        //   'xmlns:tools': 'http://schemas.android.com/tools',
+        // };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 901ee53 and 3e9f676.

📒 Files selected for processing (10)
  • .github/actions/setup/action.yml (0 hunks)
  • .github/workflows/ci.yml (0 hunks)
  • expo-plugin/src/android/index.ts (1 hunks)
  • expo-plugin/src/android/withReclaimAndroidManifest.ts (1 hunks)
  • expo-plugin/src/android/withReclaimProjectBuildGradle.ts (1 hunks)
  • expo-plugin/src/index.ts (1 hunks)
  • expo-plugin/tsconfig.json (1 hunks)
  • package.json (4 hunks)
  • tsconfig.build.json (1 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (2)
  • .github/actions/setup/action.yml
  • .github/workflows/ci.yml
✅ Files skipped from review due to trivial changes (2)
  • tsconfig.build.json
  • tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • expo-plugin/tsconfig.json
  • expo-plugin/src/android/index.ts
  • package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
expo-plugin/src/android/withReclaimProjectBuildGradle.ts (2)
expo-plugin/src/android/index.ts (1)
  • withReclaimProjectBuildGradle (2-2)
ios/inapp_rn_sdk/Api.swift (1)
  • process (541-566)
🪛 ESLint
expo-plugin/src/android/withReclaimProjectBuildGradle.ts

[error] 2-2: Delete ··

(prettier/prettier)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 7-7: Delete ··

(prettier/prettier)


[error] 8-8: Replace ····const·flutterStorageUrl·=·process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||·"https://storage.googleapis.com" with const·flutterStorageUrl·=⏎······process.env.EXPO_PUBLIC_FLUTTER_STORAGE_BASE_URL·||⏎······'https://storage.googleapis.com';

(prettier/prettier)


[error] 9-9: Replace ········const·reclaimStorageUrl·=·process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||·"https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo" with ····const·reclaimStorageUrl·=⏎······process.env.EXPO_PUBLIC_RECLAIM_STORAGE_BASE_URL·||⏎······'https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo';

(prettier/prettier)


[error] 11-11: Replace ········ with ····

(prettier/prettier)


[error] 12-12: Replace ············ with ······

(prettier/prettier)


[error] 13-13: Replace ················ with ········

(prettier/prettier)


[error] 14-14: Insert ····

(prettier/prettier)


[error] 18-18: Delete ······

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)

expo-plugin/src/android/withReclaimAndroidManifest.ts

[error] 4-4: Delete ··

(prettier/prettier)


[error] 5-5: Delete ····

(prettier/prettier)


[error] 6-6: Delete ····

(prettier/prettier)


[error] 8-8: Replace ········ with ····

(prettier/prettier)


[error] 9-9: Delete ······

(prettier/prettier)


[error] 10-10: Replace ········ with ····

(prettier/prettier)


[error] 12-13: Delete ⏎····

(prettier/prettier)


[error] 15-15: Delete ····

(prettier/prettier)


[error] 16-16: Replace ········ with ····

(prettier/prettier)


[error] 17-17: Delete ····

(prettier/prettier)


[error] 18-18: Replace ········ with ····

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ····

(prettier/prettier)


[error] 22-22: Delete ····

(prettier/prettier)


[error] 23-23: Replace ············ with ······

(prettier/prettier)


[error] 24-24: Delete ····

(prettier/prettier)


[error] 26-26: Replace ········ with ····

(prettier/prettier)


[error] 27-27: Delete ······

(prettier/prettier)


[error] 28-29: Replace ················act.$['android:name']·!=⏎··············· with ········act.$['android:name']·!=

(prettier/prettier)


[error] 30-30: Replace ········ with ····

(prettier/prettier)


[error] 32-32: Delete ····

(prettier/prettier)


[error] 33-33: Replace ············ with ······

(prettier/prettier)


[error] 34-34: Delete ········

(prettier/prettier)


[error] 35-35: Replace ················ with ········

(prettier/prettier)


[error] 36-36: Replace ················'android:configChanges': with ········'android:configChanges':⏎·········

(prettier/prettier)


[error] 37-37: Delete ········

(prettier/prettier)


[error] 38-38: Replace ················ with ········

(prettier/prettier)


[error] 39-39: Delete ······

(prettier/prettier)


[error] 40-40: Delete ····

(prettier/prettier)


[error] 42-42: Delete ····

(prettier/prettier)


[error] 43-43: Delete ··

(prettier/prettier)


[error] 44-44: Insert

(prettier/prettier)

expo-plugin/src/index.ts

[error] 1-1: Replace ·type·ConfigPlugin,·createRunOncePlugin,·withPlugins· with ⏎··type·ConfigPlugin,⏎··createRunOncePlugin,⏎··withPlugins,⏎

(prettier/prettier)


[error] 1-1: 'createRunOncePlugin' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 3-3: Delete ··

(prettier/prettier)


[error] 4-4: Delete ··

(prettier/prettier)


[error] 8-8: Delete ··

(prettier/prettier)


[error] 9-9: Delete ····

(prettier/prettier)


[error] 10-10: Delete ····

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)

🔇 Additional comments (1)
expo-plugin/src/android/withReclaimAndroidManifest.ts (1)

32-40: LGTM! Activity configuration looks comprehensive.

The ReclaimActivity configuration includes all necessary attributes for proper Android integration, including theme, configuration changes, hardware acceleration, and window soft input mode.

@@ -0,0 +1,14 @@
import { type ConfigPlugin, createRunOncePlugin, withPlugins } from '@expo/config-plugins';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unused import and fix formatting.

The createRunOncePlugin import is not used in this file and should be removed. Additionally, there are several formatting issues that need to be addressed.

Apply this diff to fix the unused import and formatting:

-import { type ConfigPlugin, createRunOncePlugin, withPlugins } from '@expo/config-plugins';
+import {
+  type ConfigPlugin,
+  withPlugins,
+} from '@expo/config-plugins';
 import {
-    withReclaimAndroidManifest,
-    withReclaimProjectBuildGradle,
+  withReclaimAndroidManifest,
+  withReclaimProjectBuildGradle,
 } from './android';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { type ConfigPlugin, createRunOncePlugin, withPlugins } from '@expo/config-plugins';
import {
type ConfigPlugin,
withPlugins,
} from '@expo/config-plugins';
import {
withReclaimAndroidManifest,
withReclaimProjectBuildGradle,
} from './android';
// …rest of the file…
🧰 Tools
🪛 ESLint

[error] 1-1: Replace ·type·ConfigPlugin,·createRunOncePlugin,·withPlugins· with ⏎··type·ConfigPlugin,⏎··createRunOncePlugin,⏎··withPlugins,⏎

(prettier/prettier)


[error] 1-1: 'createRunOncePlugin' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
In expo-plugin/src/index.ts at line 1, remove the unused import
'createRunOncePlugin' from the import statement. After removing it, reformat the
import line and the rest of the file to ensure consistent and clean code
formatting according to the project's style guidelines.

Comment on lines +26 to +30
application.activity = application.activity!.filter(
(act) =>
act.$['android:name'] !=
'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add safety check for activity array before filtering.

The code assumes application.activity exists before filtering, but it should be initialized if undefined to prevent runtime errors.

Apply this diff to add proper safety checks:

-        application.activity = application.activity!.filter(
-            (act) =>
-                act.$['android:name'] !=
-                'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
-        );
+        // Initialize activity array if it doesn't exist
+        if (!application.activity) {
+          application.activity = [];
+        }
+        
+        // Remove any existing ReclaimActivity entries
+        application.activity = application.activity.filter(
+          (act) =>
+            act.$['android:name'] !==
+            'org.reclaimprotocol.inapp_sdk.ReclaimActivity'
+        );

Also note the change from != to !== for strict equality comparison, which is preferred in TypeScript.

🧰 Tools
🪛 ESLint

[error] 26-26: Replace ········ with ····

(prettier/prettier)


[error] 27-27: Delete ······

(prettier/prettier)


[error] 28-29: Replace ················act.$['android:name']·!=⏎··············· with ········act.$['android:name']·!=

(prettier/prettier)


[error] 30-30: Replace ········ with ····

(prettier/prettier)

🤖 Prompt for AI Agents
In expo-plugin/src/android/withReclaimAndroidManifest.ts around lines 26 to 30,
the code filters application.activity without checking if it is defined, which
can cause runtime errors. Add a safety check to initialize application.activity
as an empty array if it is undefined before filtering. Also, replace the !=
operator with !== for strict equality comparison in the filter condition.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (16)
samples/example_expo/components/ui/TabBarBackground.ios.tsx (1)

17-19: Consider renaming the hook for clarity.

The function name useBottomTabOverflow is misleading since it returns the tab bar height, not overflow values. Consider renaming to better reflect its purpose.

-export function useBottomTabOverflow() {
+export function useBottomTabOverflow() {
   return useBottomTabBarHeight();
 }

Alternative names: useBottomTabHeight, useTabBarHeight, or useBottomTabBarOverflow if it's specifically meant to represent overflow handling.

README.md (1)

50-103: Excellent comprehensive Expo setup documentation.

The "Expo Only Setup" section is well-structured and covers all necessary scenarios. The warnings about Expo Go compatibility and the clear distinction between EAS and non-EAS workflows are particularly valuable.

Apply these fixes for the static analysis issues:

-Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so merge the following code to the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:
+Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so, merge the following code to the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:

Also add language specifiers to the code blocks:

-```
+```bash
 # For iOS
 npx expo prebuild
 npx expo run:ios
-```
+```bash
 # For online builds
 npx eas-cli build --profile development
samples/example_expo/components/HelloWave.tsx (1)

13-32: LGTM! Well-implemented animated component.

The HelloWave component uses react-native-reanimated effectively with:

  • Proper shared value usage
  • Correct animation sequencing and repetition
  • Appropriate cleanup with dependency array
  • Good integration with ThemedText for consistency

Apply this formatting fix for prettier:

-    rotationAnimation.value = withRepeat(
-      withSequence(withTiming(25, { duration: 150 }), withTiming(0, { duration: 150 })),
-      4 // Run the animation 4 times
-    );
+    rotationAnimation.value = withRepeat(
+      withSequence(
+        withTiming(25, { duration: 150 }),
+        withTiming(0, { duration: 150 })
+      ),
+      4 // Run the animation 4 times
+    );
samples/example_expo/app/_layout.tsx (1)

9-29: LGTM! Well-structured root layout with proper theme and navigation setup.

The implementation correctly handles:

  • Asynchronous font loading with appropriate loading state
  • Theme provider integration with color scheme detection
  • Navigation stack configuration
  • Status bar styling

Apply these formatting fixes for prettier:

-import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
+import {
+  DarkTheme,
+  DefaultTheme,
+  ThemeProvider,
+} from '@react-navigation/native';
-      <Stack >
+      <Stack>
samples/example_expo/components/ThemedView.tsx (1)

1-14: LGTM! Well-structured themed component with minor formatting issues.

The ThemedView component is cleanly implemented and correctly integrates with the theming system. The type definitions and logic are sound.

However, please address the Prettier formatting issues flagged by ESLint to maintain code consistency:

-export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
-  const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
+export function ThemedView({
+  style,
+  lightColor,
+  darkColor,
+  ...otherProps
+}: ThemedViewProps) {
+  const backgroundColor = useThemeColor(
+    { light: lightColor, dark: darkColor },
+    'background'
+  );
samples/example_expo/android/build.gradle (1)

18-24: Consider adding error handling for dynamic React Native path resolution.

The dynamic resolution of the React Native Android directory is clever but could be fragile if Node.js is unavailable or if the command fails. Consider adding error handling or a fallback mechanism.

You could wrap this in a try-catch or provide a fallback path:

def reactNativeAndroidDir
try {
  reactNativeAndroidDir = new File(
    providers.exec {
      workingDir(rootDir)
      commandLine("node", "--print", "require.resolve('react-native/package.json')")
    }.standardOutput.asText.get().trim(),
    "../android"
  )
} catch (Exception e) {
  // Fallback to a default path or throw a more descriptive error
  throw new GradleException("Failed to resolve React Native Android directory: ${e.message}")
}
samples/example_expo/components/ExternalLink.tsx (1)

1-24: Excellent cross-platform external link handling!

The ExternalLink component elegantly handles the differences between web and native platforms. The type definition using intersection types is well-crafted, and the platform-specific logic correctly prevents default navigation on native while opening in-app browser.

Minor formatting issue to address:

-type Props = Omit<ComponentProps<typeof Link>, 'href'> & { href: Href & string };
+type Props = Omit<ComponentProps<typeof Link>, 'href'> & {
+  href: Href & string;
+};
samples/example_expo/components/ui/IconSymbol.tsx (2)

28-41: Good cross-platform icon abstraction with a few considerations.

The mapping approach is solid for ensuring consistent iconography across platforms. However, there are a couple of points to address:

  1. The weight parameter is declared but not used in the implementation
  2. The icon mapping is quite limited - consider how new icons will be added

Consider either removing the unused weight parameter or documenting why it's kept for future use:

export function IconSymbol({
  name,
  size = 24,
  color,
  style,
}: {
  name: IconSymbolName;
  size?: number;
  color: string | OpaqueColorValue;
  style?: StyleProp<TextStyle>;
-  weight?: SymbolWeight;
}) {

Alternatively, add a comment explaining its purpose for iOS platform compatibility.


16-21: Consider expanding the icon mapping or documenting the addition process.

The current mapping only includes 4 icons. Consider:

  1. Adding more commonly used icons
  2. Documenting the process for adding new icons
  3. Creating a utility or script to help with mapping
samples/example_expo/components/Collapsible.tsx (1)

10-33: Well-implemented collapsible component!

The Collapsible component is cleanly designed with:

  • Proper state management for open/closed state
  • Good use of themed components
  • Nice visual feedback with the rotating chevron
  • Appropriate accessibility with TouchableOpacity

The logic and theming integration are solid.

Please address the minor formatting issues:

-export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
+export function Collapsible({
+  children,
+  title,
+}: PropsWithChildren & { title: string }) {
        onPress={() => setIsOpen((value) => !value)}
-        activeOpacity={0.8}>
+        activeOpacity={0.8}
+      >
samples/example_expo/components/ThemedText.tsx (2)

22-30: Simplify conditional style application

The multiple ternary operators for style selection can be simplified using array indexing or a style mapping approach for better readability and performance.

Consider this refactor:

+const typeStyles = {
+  default: styles.default,
+  title: styles.title,
+  defaultSemiBold: styles.defaultSemiBold,
+  subtitle: styles.subtitle,
+  link: styles.link,
+};

  return (
    <Text
      style={[
        { color },
-        type === 'default' ? styles.default : undefined,
-        type === 'title' ? styles.title : undefined,
-        type === 'defaultSemiBold' ? styles.defaultSemiBold : undefined,
-        type === 'subtitle' ? styles.subtitle : undefined,
-        type === 'link' ? styles.link : undefined,
+        typeStyles[type],
        style,
      ]}
      {...rest}
    />
  );

55-60: Consider making link color theme-aware

The link style has a hardcoded color that won't adapt to theme changes. Consider using the theme color system for consistency.

  link: {
    lineHeight: 30,
    fontSize: 16,
-    color: '#0a7ea4',
+    // Remove hardcoded color, let the component's color prop handle theming
  },

Then ensure the component receives appropriate link colors via the lightColor and darkColor props when type="link".

samples/example_expo/scripts/reset-project.js (1)

104-111: Consider improving input validation

The current validation only checks for 'y' or 'n', but could be more user-friendly by accepting variations like 'yes', 'no', 'Y', 'N'.

-    if (userInput === "y" || userInput === "n") {
+    if (['y', 'yes', 'n', 'no'].includes(userInput)) {
       moveDirectories(userInput).finally(() => rl.close());
     } else {
-      console.log("❌ Invalid input. Please enter 'Y' or 'N'.");
+      console.log("❌ Invalid input. Please enter 'Y', 'yes', 'N', or 'no'.");
       rl.close();
     }
samples/example_expo/components/ParallaxScrollView.tsx (1)

30-45: Fix code formatting as indicated by ESLint

The static analysis tools have identified formatting issues that should be addressed for consistency.

Apply these formatting fixes:

        {
          scale: interpolate(
-            scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]
+            scrollOffset.value,
+            [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
+            [2, 1, 1]
          ),
        },
samples/example_expo/app/(home)/_layout.tsx (1)

1-2: Remove commented import statement.

The commented import on line 1 appears to be dead code and should be removed.

-// import { ReclaimVerification } from '@reclaimprotocol/inapp-rn-sdk';
 import { ReclaimVerification } from '@reclaimprotocol/inapp-rn-sdk';
samples/example_expo/android/app/build.gradle (1)

90-97: Consider using a more specific application ID for production.

The application ID org.example.expo is clearly for example purposes. Ensure this is updated to a proper package name before production use.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e9f676 and a5fb22e.

⛔ Files ignored due to path filters (20)
  • samples/example_expo/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png is excluded by !**/*.png
  • samples/example_expo/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png is excluded by !**/*.png
  • samples/example_expo/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png is excluded by !**/*.png
  • samples/example_expo/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png is excluded by !**/*.png
  • samples/example_expo/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png is excluded by !**/*.png
  • samples/example_expo/android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • samples/example_expo/assets/fonts/SpaceMono-Regular.ttf is excluded by !**/*.ttf
  • samples/example_expo/assets/images/adaptive-icon.png is excluded by !**/*.png
  • samples/example_expo/assets/images/favicon.png is excluded by !**/*.png
  • samples/example_expo/assets/images/icon.png is excluded by !**/*.png
  • samples/example_expo/assets/images/partial-react-logo.png is excluded by !**/*.png
  • samples/example_expo/assets/images/react-logo.png is excluded by !**/*.png
  • samples/example_expo/assets/images/react-logo@2x.png is excluded by !**/*.png
  • samples/example_expo/assets/images/react-logo@3x.png is excluded by !**/*.png
  • samples/example_expo/assets/images/splash-icon.png is excluded by !**/*.png
  • samples/example_expo/ios/Podfile.lock is excluded by !**/*.lock
  • samples/example_expo/ios/exampleexpo/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png is excluded by !**/*.png
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenLogo.imageset/image.png is excluded by !**/*.png
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenLogo.imageset/image@2x.png is excluded by !**/*.png
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenLogo.imageset/image@3x.png is excluded by !**/*.png
📒 Files selected for processing (68)
  • README.md (2 hunks)
  • package.json (4 hunks)
  • samples/example_expo/.env.example (1 hunks)
  • samples/example_expo/.gitignore (1 hunks)
  • samples/example_expo/README.md (1 hunks)
  • samples/example_expo/android/.gitignore (1 hunks)
  • samples/example_expo/android/app/build.gradle (1 hunks)
  • samples/example_expo/android/app/proguard-rules.pro (1 hunks)
  • samples/example_expo/android/app/src/debug/AndroidManifest.xml (1 hunks)
  • samples/example_expo/android/app/src/main/AndroidManifest.xml (1 hunks)
  • samples/example_expo/android/app/src/main/java/org/example/expo/MainActivity.kt (1 hunks)
  • samples/example_expo/android/app/src/main/java/org/example/expo/MainApplication.kt (1 hunks)
  • samples/example_expo/android/app/src/main/res/drawable/ic_launcher_background.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/drawable/rn_edit_text_material.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/values-night/colors.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/values/colors.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/values/strings.xml (1 hunks)
  • samples/example_expo/android/app/src/main/res/values/styles.xml (1 hunks)
  • samples/example_expo/android/build.gradle (1 hunks)
  • samples/example_expo/android/gradle.properties (1 hunks)
  • samples/example_expo/android/gradle/wrapper/gradle-wrapper.properties (1 hunks)
  • samples/example_expo/android/gradlew (1 hunks)
  • samples/example_expo/android/gradlew.bat (1 hunks)
  • samples/example_expo/android/settings.gradle (1 hunks)
  • samples/example_expo/app.json (1 hunks)
  • samples/example_expo/app/(home)/_layout.tsx (1 hunks)
  • samples/example_expo/app/+not-found.tsx (1 hunks)
  • samples/example_expo/app/_layout.tsx (1 hunks)
  • samples/example_expo/components/Collapsible.tsx (1 hunks)
  • samples/example_expo/components/ExternalLink.tsx (1 hunks)
  • samples/example_expo/components/HapticTab.tsx (1 hunks)
  • samples/example_expo/components/HelloWave.tsx (1 hunks)
  • samples/example_expo/components/ParallaxScrollView.tsx (1 hunks)
  • samples/example_expo/components/ThemedText.tsx (1 hunks)
  • samples/example_expo/components/ThemedView.tsx (1 hunks)
  • samples/example_expo/components/ui/IconSymbol.ios.tsx (1 hunks)
  • samples/example_expo/components/ui/IconSymbol.tsx (1 hunks)
  • samples/example_expo/components/ui/TabBarBackground.ios.tsx (1 hunks)
  • samples/example_expo/components/ui/TabBarBackground.tsx (1 hunks)
  • samples/example_expo/constants/Colors.ts (1 hunks)
  • samples/example_expo/eslint.config.js (1 hunks)
  • samples/example_expo/hooks/useColorScheme.ts (1 hunks)
  • samples/example_expo/hooks/useColorScheme.web.ts (1 hunks)
  • samples/example_expo/hooks/useThemeColor.ts (1 hunks)
  • samples/example_expo/ios/.gitignore (1 hunks)
  • samples/example_expo/ios/.xcode.env (1 hunks)
  • samples/example_expo/ios/Podfile (1 hunks)
  • samples/example_expo/ios/Podfile.properties.json (1 hunks)
  • samples/example_expo/ios/exampleexpo.xcodeproj/project.pbxproj (1 hunks)
  • samples/example_expo/ios/exampleexpo.xcodeproj/xcshareddata/xcschemes/exampleexpo.xcscheme (1 hunks)
  • samples/example_expo/ios/exampleexpo.xcworkspace/contents.xcworkspacedata (1 hunks)
  • samples/example_expo/ios/exampleexpo/AppDelegate.swift (1 hunks)
  • samples/example_expo/ios/exampleexpo/Images.xcassets/AppIcon.appiconset/Contents.json (1 hunks)
  • samples/example_expo/ios/exampleexpo/Images.xcassets/Contents.json (1 hunks)
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenBackground.colorset/Contents.json (1 hunks)
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenLogo.imageset/Contents.json (1 hunks)
  • samples/example_expo/ios/exampleexpo/Info.plist (1 hunks)
  • samples/example_expo/ios/exampleexpo/PrivacyInfo.xcprivacy (1 hunks)
  • samples/example_expo/ios/exampleexpo/SplashScreen.storyboard (1 hunks)
  • samples/example_expo/ios/exampleexpo/Supporting/Expo.plist (1 hunks)
  • samples/example_expo/ios/exampleexpo/exampleexpo-Bridging-Header.h (1 hunks)
  • samples/example_expo/ios/exampleexpo/exampleexpo.entitlements (1 hunks)
  • samples/example_expo/package.json (1 hunks)
  • samples/example_expo/scripts/reset-project.js (1 hunks)
  • samples/example_expo/tsconfig.json (1 hunks)
  • user-workspace/src/App.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (44)
  • samples/example_expo/android/app/src/main/res/values-night/colors.xml
  • samples/example_expo/ios/exampleexpo/exampleexpo-Bridging-Header.h
  • user-workspace/src/App.tsx
  • samples/example_expo/.env.example
  • samples/example_expo/ios/exampleexpo.xcworkspace/contents.xcworkspacedata
  • samples/example_expo/hooks/useColorScheme.ts
  • samples/example_expo/ios/exampleexpo/Images.xcassets/Contents.json
  • samples/example_expo/ios/exampleexpo/exampleexpo.entitlements
  • samples/example_expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  • samples/example_expo/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  • samples/example_expo/ios/Podfile.properties.json
  • samples/example_expo/android/app/src/main/res/values/colors.xml
  • samples/example_expo/constants/Colors.ts
  • samples/example_expo/android/app/src/main/res/drawable/ic_launcher_background.xml
  • samples/example_expo/android/gradle/wrapper/gradle-wrapper.properties
  • samples/example_expo/components/ui/TabBarBackground.tsx
  • samples/example_expo/android/app/proguard-rules.pro
  • samples/example_expo/tsconfig.json
  • samples/example_expo/android/.gitignore
  • samples/example_expo/components/ui/IconSymbol.ios.tsx
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenBackground.colorset/Contents.json
  • samples/example_expo/ios/.xcode.env
  • samples/example_expo/ios/exampleexpo/Images.xcassets/AppIcon.appiconset/Contents.json
  • samples/example_expo/eslint.config.js
  • samples/example_expo/ios/exampleexpo/Images.xcassets/SplashScreenLogo.imageset/Contents.json
  • samples/example_expo/ios/exampleexpo/PrivacyInfo.xcprivacy
  • samples/example_expo/android/app/src/debug/AndroidManifest.xml
  • samples/example_expo/components/HapticTab.tsx
  • samples/example_expo/ios/.gitignore
  • samples/example_expo/ios/exampleexpo/Supporting/Expo.plist
  • samples/example_expo/android/app/src/main/res/values/styles.xml
  • samples/example_expo/.gitignore
  • samples/example_expo/hooks/useColorScheme.web.ts
  • samples/example_expo/app.json
  • samples/example_expo/android/gradlew.bat
  • samples/example_expo/app/+not-found.tsx
  • samples/example_expo/package.json
  • samples/example_expo/android/app/src/main/res/drawable/rn_edit_text_material.xml
  • samples/example_expo/android/app/src/main/res/values/strings.xml
  • samples/example_expo/ios/exampleexpo/SplashScreen.storyboard
  • samples/example_expo/android/gradle.properties
  • samples/example_expo/ios/exampleexpo.xcodeproj/xcshareddata/xcschemes/exampleexpo.xcscheme
  • samples/example_expo/hooks/useThemeColor.ts
  • samples/example_expo/ios/exampleexpo/Info.plist
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🧬 Code Graph Analysis (5)
samples/example_expo/components/ThemedView.tsx (1)
samples/example_expo/hooks/useThemeColor.ts (1)
  • useThemeColor (9-21)
samples/example_expo/components/HelloWave.tsx (1)
samples/example_expo/components/ThemedText.tsx (1)
  • ThemedText (11-34)
samples/example_expo/components/Collapsible.tsx (3)
samples/example_expo/components/ThemedView.tsx (1)
  • ThemedView (10-14)
samples/example_expo/constants/Colors.ts (1)
  • Colors (9-26)
samples/example_expo/components/ThemedText.tsx (1)
  • ThemedText (11-34)
samples/example_expo/components/ThemedText.tsx (1)
samples/example_expo/hooks/useThemeColor.ts (1)
  • useThemeColor (9-21)
samples/example_expo/components/ParallaxScrollView.tsx (1)
samples/example_expo/components/ThemedView.tsx (1)
  • ThemedView (10-14)
🪛 ESLint
samples/example_expo/components/ThemedView.tsx

[error] 10-10: Replace ·style,·lightColor,·darkColor,·...otherProps· with ⏎··style,⏎··lightColor,⏎··darkColor,⏎··...otherProps⏎

(prettier/prettier)


[error] 11-11: Replace {·light:·lightColor,·dark:·darkColor·},·'background' with ⏎····{·light:·lightColor,·dark:·darkColor·},⏎····'background'⏎··

(prettier/prettier)

samples/example_expo/components/HelloWave.tsx

[error] 18-18: Replace withTiming(25,·{·duration:·150·}),·withTiming(0,·{·duration:·150·}) with ⏎········withTiming(25,·{·duration:·150·}),⏎········withTiming(0,·{·duration:·150·})⏎······

(prettier/prettier)

samples/example_expo/app/_layout.tsx

[error] 1-1: Replace ·DarkTheme,·DefaultTheme,·ThemeProvider· with ⏎··DarkTheme,⏎··DefaultTheme,⏎··ThemeProvider,⏎

(prettier/prettier)


[error] 22-22: Delete ·

(prettier/prettier)

samples/example_expo/components/ExternalLink.tsx

[error] 6-6: Replace ·href:·Href·&·string· with ⏎··href:·Href·&·string;⏎

(prettier/prettier)

samples/example_expo/components/Collapsible.tsx

[error] 10-10: Replace ·children,·title· with ⏎··children,⏎··title,⏎

(prettier/prettier)


[error] 19-19: Insert ⏎······

(prettier/prettier)

samples/example_expo/components/ui/IconSymbol.tsx

[error] 8-8: Replace SymbolViewProps['name'],·ComponentProps<typeof·MaterialIcons>['name'] with ⏎··SymbolViewProps['name'],⏎··ComponentProps<typeof·MaterialIcons>['name']⏎

(prettier/prettier)


[error] 40-40: Replace <MaterialIcons·color={color}·size={size}·name={MAPPING[name]}·style={style}·/> with (⏎····<MaterialIcons⏎······color={color}⏎······size={size}⏎······name={MAPPING[name]}⏎······style={style}⏎····/>⏎··)

(prettier/prettier)

samples/example_expo/app/(home)/_layout.tsx

[error] 4-4: Replace ·Button,·Clipboard,·ScrollView,·Text,·TextInput,·View· with ⏎··Button,⏎··Clipboard,⏎··ScrollView,⏎··Text,⏎··TextInput,⏎··View,⏎

(prettier/prettier)


[error] 9-9: Delete ··

(prettier/prettier)


[error] 10-10: Delete ··

(prettier/prettier)


[error] 11-11: Insert ;

(prettier/prettier)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 15-15: Delete ··

(prettier/prettier)


[error] 16-16: Replace ··const·[result,·setResult]·=·useState<ReclaimVerification.Response·|·null>(null with const·[result,·setResult]·=·useState<ReclaimVerification.Response·|·null>(⏎····null⏎··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Replace ········ with ····

(prettier/prettier)


[error] 20-20: Delete ······

(prettier/prettier)


[error] 21-21: Delete ········

(prettier/prettier)


[error] 22-22: Replace ················ with ········

(prettier/prettier)


[error] 23-23: Delete ······

(prettier/prettier)


[error] 24-24: Replace ············ with ······

(prettier/prettier)


[error] 25-25: Delete ····

(prettier/prettier)


[error] 26-26: Replace ····console.assert(config.REACT_APP_RECLAIM_APP_ID,·'RECLAIM_APP_ID·is·not·set'); with console.assert(⏎······config.REACT_APP_RECLAIM_APP_ID,⏎······'RECLAIM_APP_ID·is·not·set'

(prettier/prettier)


[error] 27-27: Replace ····console.assert(config.REACT_APP_RECLAIM_APP_SECRET,·'RECLAIM_APP_SECRET·is·not·set'); with );⏎····console.assert(⏎······config.REACT_APP_RECLAIM_APP_SECRET,⏎······'RECLAIM_APP_SECRET·is·not·set'

(prettier/prettier)


[error] 28-28: Insert );⏎

(prettier/prettier)


[error] 29-29: Delete ······

(prettier/prettier)


[error] 30-30: Replace ············ with ······

(prettier/prettier)


[error] 31-31: Delete ········

(prettier/prettier)


[error] 32-32: Delete ········

(prettier/prettier)


[error] 33-33: Delete ········

(prettier/prettier)


[error] 34-34: Delete ······

(prettier/prettier)


[error] 35-35: Replace ············ with ······

(prettier/prettier)


[error] 36-36: Delete ····

(prettier/prettier)


[error] 37-37: Replace ············ with ······

(prettier/prettier)


[error] 38-38: Replace ················ with ········

(prettier/prettier)


[error] 39-39: Delete ······

(prettier/prettier)


[error] 40-40: Delete ······

(prettier/prettier)


[error] 41-41: Replace ················ with ········

(prettier/prettier)


[error] 42-42: Delete ··········

(prettier/prettier)


[error] 43-43: Replace ························ with ············

(prettier/prettier)


[error] 44-44: Replace ···························· with ··············

(prettier/prettier)


[error] 45-45: Replace ···························· with ··············

(prettier/prettier)


[error] 46-46: Replace ························ with ············

(prettier/prettier)


[error] 47-47: Replace ························ with ············

(prettier/prettier)


[error] 48-48: Delete ··········

(prettier/prettier)


[error] 49-49: Replace ························ with ············

(prettier/prettier)


[error] 50-50: Replace ···························· with ··············

(prettier/prettier)


[error] 51-51: Delete ··············

(prettier/prettier)


[error] 52-52: Delete ············

(prettier/prettier)


[error] 53-53: Replace ························ with ············

(prettier/prettier)


[error] 54-54: Delete ··········

(prettier/prettier)


[error] 55-55: Replace ························ with ············

(prettier/prettier)


[error] 56-56: Delete ··············

(prettier/prettier)


[error] 57-57: Replace ···························· with ··············

(prettier/prettier)


[error] 58-58: Delete ············

(prettier/prettier)


[error] 59-59: Replace ························ with ············

(prettier/prettier)


[error] 60-60: Delete ··········

(prettier/prettier)


[error] 61-61: Delete ··········

(prettier/prettier)


[error] 62-62: Replace ························ with ············

(prettier/prettier)


[error] 63-63: Delete ··············

(prettier/prettier)


[error] 64-64: Replace ···························· with ··············

(prettier/prettier)


[error] 65-65: Replace ························ with ············

(prettier/prettier)


[error] 66-66: Replace ················ with ········

(prettier/prettier)


[error] 67-67: Replace ············ with ······

(prettier/prettier)


[error] 68-68: Delete ········

(prettier/prettier)


[error] 69-69: Replace ··········text:·error·instanceof·Error·?·error.message with text:⏎············error·instanceof·Error⏎··············?·error.message⏎·············

(prettier/prettier)


[error] 70-70: Replace ···················· with ··········

(prettier/prettier)


[error] 71-71: Delete ········

(prettier/prettier)


[error] 72-72: Replace ············ with ······

(prettier/prettier)


[error] 73-73: Replace ········ with ····

(prettier/prettier)


[error] 74-74: Delete ··

(prettier/prettier)


[error] 76-76: Delete ··

(prettier/prettier)


[error] 77-77: Delete ····

(prettier/prettier)


[error] 78-78: Replace ············ with ······

(prettier/prettier)


[error] 79-79: Delete ········

(prettier/prettier)


[error] 80-80: Delete ········

(prettier/prettier)


[error] 81-81: Delete ······

(prettier/prettier)


[error] 82-82: Replace ············ with ······

(prettier/prettier)


[error] 83-83: Delete ····

(prettier/prettier)


[error] 85-85: Replace ········ with ····

(prettier/prettier)


[error] 86-86: Delete ······

(prettier/prettier)


[error] 87-87: Replace ······const·verificationResult·= with const·verificationResult·=⏎·······

(prettier/prettier)


[error] 88-88: Delete ······

(prettier/prettier)


[error] 89-89: Delete ····

(prettier/prettier)


[error] 90-90: Replace ············ with ······

(prettier/prettier)


[error] 91-91: Delete ········

(prettier/prettier)


[error] 92-92: Delete ······

(prettier/prettier)


[error] 93-93: Replace ············ with ······

(prettier/prettier)


[error] 94-94: Delete ········

(prettier/prettier)


[error] 95-95: Replace ···················· with ··········

(prettier/prettier)


[error] 96-96: Delete ············

(prettier/prettier)


[error] 97-97: Replace ···························· with ··············

(prettier/prettier)


[error] 98-98: Replace ···························· with ··············

(prettier/prettier)


[error] 99-99: Delete ············

(prettier/prettier)


[error] 100-100: Delete ············

(prettier/prettier)


[error] 101-101: Delete ··········

(prettier/prettier)


[error] 102-102: Delete ············

(prettier/prettier)


[error] 103-103: Replace ···························· with ··············

(prettier/prettier)


[error] 104-104: Replace ···························· with ··············

(prettier/prettier)


[error] 105-105: Replace ························ with ············

(prettier/prettier)


[error] 106-106: Replace ························ with ············

(prettier/prettier)


[error] 107-107: Delete ··········

(prettier/prettier)


[error] 108-108: Delete ············

(prettier/prettier)


[error] 109-109: Delete ··············

(prettier/prettier)


[error] 110-110: Replace ···························· with ··············

(prettier/prettier)


[error] 111-111: Replace ························ with ············

(prettier/prettier)


[error] 112-112: Replace ························ with ············

(prettier/prettier)


[error] 113-113: Replace ···················· with ··········

(prettier/prettier)


[error] 114-114: Delete ··········

(prettier/prettier)


[error] 115-115: Replace ························ with ············

(prettier/prettier)


[error] 116-116: Replace ···························· with ··············

(prettier/prettier)


[error] 117-117: Replace ···························· with ··············

(prettier/prettier)


[error] 118-118: Delete ············

(prettier/prettier)


[error] 119-119: Replace ················ with ········

(prettier/prettier)


[error] 120-120: Replace ············ with ······

(prettier/prettier)


[error] 121-121: Replace ················ with ········

(prettier/prettier)


[error] 122-122: Replace ··········text:·error·instanceof·Error·?·error.message with text:⏎············error·instanceof·Error⏎··············?·error.message⏎·············

(prettier/prettier)


[error] 123-123: Delete ··········

(prettier/prettier)


[error] 124-124: Replace ················ with ········

(prettier/prettier)


[error] 125-125: Replace ············ with ······

(prettier/prettier)


[error] 126-126: Delete ····

(prettier/prettier)


[error] 127-127: Replace ··} with };

(prettier/prettier)


[error] 129-129: Replace ···· with ··

(prettier/prettier)


[error] 130-130: Delete ····

(prettier/prettier)


[error] 131-131: Replace ············ with ······

(prettier/prettier)


[error] 132-132: Replace ················ with ········

(prettier/prettier)


[error] 133-133: Delete ········

(prettier/prettier)


[error] 134-134: Delete ······

(prettier/prettier)


[error] 135-135: Replace ············ with ······

(prettier/prettier)


[error] 136-136: Delete ····

(prettier/prettier)


[error] 137-137: Replace ········ with ····

(prettier/prettier)


[error] 138-138: Delete ······

(prettier/prettier)


[error] 139-139: Replace ············ with ······

(prettier/prettier)


[error] 140-140: Delete ········

(prettier/prettier)


[error] 141-141: Replace ················ with ········

(prettier/prettier)


[error] 142-142: Delete ······

(prettier/prettier)


[error] 143-143: Replace ········ with ····

(prettier/prettier)


[error] 144-144: Delete ······

(prettier/prettier)


[error] 145-145: Delete ········

(prettier/prettier)


[error] 146-146: Delete ········

(prettier/prettier)


[error] 147-147: Replace ············ with ······

(prettier/prettier)


[error] 148-148: Replace ········ with ····

(prettier/prettier)


[error] 149-149: Replace ····} with ··};

(prettier/prettier)


[error] 151-151: Delete ··

(prettier/prettier)


[error] 152-152: Delete ····

(prettier/prettier)


[error] 153-153: Replace ············ with ······

(prettier/prettier)


[error] 154-154: Replace ············ with ······

(prettier/prettier)


[error] 155-155: Delete ······

(prettier/prettier)


[error] 156-156: Replace ················ with ········

(prettier/prettier)


[error] 157-157: Replace ···················· with ··········

(prettier/prettier)


[error] 158-158: Replace ···················· with ··········

(prettier/prettier)


[error] 159-159: Delete ········

(prettier/prettier)


[error] 160-160: Replace ············ with ······

(prettier/prettier)


[error] 161-161: Delete ····

(prettier/prettier)


[error] 162-162: Replace ············ with ······

(prettier/prettier)


[error] 163-163: Replace ············ with ······

(prettier/prettier)


[error] 164-164: Delete ········

(prettier/prettier)


[error] 165-165: Delete ········

(prettier/prettier)


[error] 166-166: Delete ······

(prettier/prettier)


[error] 167-167: Replace ········ with ····

(prettier/prettier)


[error] 168-168: Delete ··

(prettier/prettier)


[error] 170-170: Delete ··

(prettier/prettier)


[error] 171-171: Delete ····

(prettier/prettier)


[error] 172-172: Replace ······<Text·style={{·fontSize:·24,·fontWeight:·'bold',·textAlign:·'center',·marginBottom:·20,·color:·'#000000'·}}> with <Text⏎········style={{⏎··········fontSize:·24,⏎··········fontWeight:·'bold',⏎··········textAlign:·'center',⏎··········marginBottom:·20,⏎··········color:·'#000000',⏎········}}

(prettier/prettier)


[error] 173-173: Replace ········ with ······>⏎

(prettier/prettier)


[error] 174-174: Delete ······

(prettier/prettier)


[error] 176-176: Delete ······

(prettier/prettier)


[error] 177-177: Replace ········<Text·style={{·fontSize:·16,·fontWeight:·'600',·marginBottom:·8,·color:·'#000000'·}}> with <Text⏎··········style={{⏎············fontSize:·16,⏎············fontWeight:·'600',⏎············marginBottom:·8,⏎············color:·'#000000',⏎··········}}

(prettier/prettier)


[error] 178-178: Replace ·· with >⏎

(prettier/prettier)


[error] 179-179: Delete ········

(prettier/prettier)


[error] 180-180: Replace ················ with ········

(prettier/prettier)


[error] 181-181: Replace ···················· with ··········

(prettier/prettier)


[error] 182-182: Replace ························ with ············

(prettier/prettier)


[error] 183-183: Delete ············

(prettier/prettier)


[error] 184-184: Replace ························ with ············

(prettier/prettier)


[error] 185-185: Replace ························ with ············

(prettier/prettier)


[error] 186-186: Replace ························ with ············

(prettier/prettier)


[error] 187-187: Replace ························ with ············

(prettier/prettier)


[error] 188-188: Delete ··········

(prettier/prettier)


[error] 189-189: Delete ··········

(prettier/prettier)


[error] 190-190: Replace ···················· with ··········

(prettier/prettier)


[error] 191-191: Replace ···················· with ··········

(prettier/prettier)


[error] 192-192: Replace ···················· with ··········

(prettier/prettier)


[error] 193-193: Delete ········

(prettier/prettier)


[error] 194-194: Delete ······

(prettier/prettier)


[error] 196-199: Replace ············<Button⏎················title="Start·Verification"⏎················onPress={handleStartVerification}⏎··········· with ······<Button·title="Start·Verification"·onPress={handleStartVerification}

(prettier/prettier)


[error] 201-201: Replace ······<Text·style={{·flex:·0,·padding:·16,·textAlign:·'center',·color:·'#000000',·fontWeight:·'bold'·}}>OR with <Text⏎········style={{⏎··········flex:·0,⏎··········padding:·16,⏎··········textAlign:·'center',⏎··········color:·'#000000',⏎··········fontWeight:·'bold',⏎········}}⏎······>⏎········OR⏎······

(prettier/prettier)


[error] 203-203: Delete ······

(prettier/prettier)


[error] 204-204: Replace ········<Text·style={{·fontSize:·16,·fontWeight:·'600',·marginBottom:·8,·color:·'#000000'·}}> with <Text⏎··········style={{⏎············fontSize:·16,⏎············fontWeight:·'600',⏎············marginBottom:·8,⏎············color:·'#000000',⏎··········}}

(prettier/prettier)


[error] 205-205: Replace ·· with >⏎

(prettier/prettier)


[error] 206-206: Delete ········

(prettier/prettier)


[error] 207-207: Replace ················ with ········

(prettier/prettier)


[error] 208-208: Replace ···················· with ··········

(prettier/prettier)


[error] 209-209: Replace ························ with ············

(prettier/prettier)


[error] 210-210: Replace ························ with ············

(prettier/prettier)


[error] 211-211: Delete ············

(prettier/prettier)


[error] 212-212: Replace ························ with ············

(prettier/prettier)


[error] 213-213: Replace ························ with ············

(prettier/prettier)


[error] 214-214: Delete ············

(prettier/prettier)


[error] 215-215: Replace ···················· with ··········

(prettier/prettier)


[error] 216-216: Delete ··········

(prettier/prettier)


[error] 217-217: Replace ···················· with ··········

(prettier/prettier)


[error] 218-218: Delete ··········

(prettier/prettier)


[error] 219-219: Delete ··········

(prettier/prettier)


[error] 220-220: Delete ········

(prettier/prettier)


[error] 221-221: Delete ······

(prettier/prettier)


[error] 223-223: Replace ············ with ······

(prettier/prettier)


[error] 224-224: Replace ················ with ········

(prettier/prettier)


[error] 225-225: Delete ········

(prettier/prettier)


[error] 226-226: Delete ······

(prettier/prettier)


[error] 228-228: Replace ············ with ······

(prettier/prettier)


[error] 229-229: Replace ············<ScrollView with ······<ScrollView⏎·······

(prettier/prettier)


[error] 230-230: Replace ················ with ··········

(prettier/prettier)


[error] 231-231: Replace ················ with ··········

(prettier/prettier)


[error] 232-232: Delete ······

(prettier/prettier)


[error] 233-233: Replace ················ with ··········

(prettier/prettier)


[error] 234-234: Replace ················ with ··········

(prettier/prettier)


[error] 235-235: Delete ······

(prettier/prettier)


[error] 236-236: Replace ············}}> with ········}}

(prettier/prettier)


[error] 237-237: Replace ··········<Text with >⏎········<Text⏎·········

(prettier/prettier)


[error] 238-238: Delete ········

(prettier/prettier)


[error] 239-239: Replace ······}}··> with }}

(prettier/prettier)


[error] 240-240: Replace ·········· with ········>⏎

(prettier/prettier)


[error] 241-241: Delete ········

(prettier/prettier)


[error] 242-242: Replace ················ with ········

(prettier/prettier)


[error] 243-243: Replace ··········<Text with <Text⏎···········

(prettier/prettier)


[error] 244-244: Replace ························ with ··············

(prettier/prettier)


[error] 245-245: Replace ········}}·onPress={copyProof}·> with }}⏎············onPress={copyProof}

(prettier/prettier)


[error] 246-246: Replace ·· with >⏎

(prettier/prettier)


[error] 247-247: Delete ··········

(prettier/prettier)


[error] 248-248: Delete ········

(prettier/prettier)


[error] 249-249: Delete ······

(prettier/prettier)


[error] 251-251: Delete ······

(prettier/prettier)


[error] 252-255: Replace ················<Button⏎····················title="Ping"⏎····················onPress={onPing}⏎··············· with ········<Button·title="Ping"·onPress={onPing}

(prettier/prettier)


[error] 256-256: Replace ············ with ······

(prettier/prettier)


[error] 257-259: Delete ⏎⏎····

(prettier/prettier)


[error] 260-260: Delete ··

(prettier/prettier)

samples/example_expo/components/ParallaxScrollView.tsx

[error] 41-41: Replace scrollOffset.value,·[-HEADER_HEIGHT,·0,·HEADER_HEIGHT],·[2,·1,·1] with ⏎············scrollOffset.value,⏎············[-HEADER_HEIGHT,·0,·HEADER_HEIGHT],⏎············[2,·1,·1]⏎··········

(prettier/prettier)


[error] 53-53: Insert ⏎······

(prettier/prettier)


[error] 59-59: Insert ⏎········

(prettier/prettier)

🪛 LanguageTool
README.md

[uncategorized] ~52-~52: Possible missing comma found.
Context: ... the Reclaim InApp Config Plugin. To do so merge the following code to the plugins...

(AI_HYDRA_LEO_MISSING_COMMA)

samples/example_expo/README.md

[style] ~27-~27: Consider using “incompatible” to avoid wordiness.
Context: ...ent with Expo Note: This plugin is not compatible with Expo Go. Please use a development ...

(NOT_ABLE_PREMIUM)


[uncategorized] ~52-~52: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...https://github.com/expo/expo): View our open source platform and contribute. - [Discord com...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


92-92: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

🪛 Biome (1.9.4)
samples/example_expo/app/(home)/_layout.tsx

[error] 60-60: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)


[error] 113-113: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)

🪛 RuboCop (1.75.5)
samples/example_expo/ios/Podfile

[convention] 5-5: Avoid using rescue in its modifier form.

(Style/RescueModifier)


[convention] 28-28: Put a comma after the last item of a multiline array.

(Style/TrailingCommaInArrayLiteral)


[convention] 42-42: Avoid comma after the last parameter of a method call.

(Style/TrailingCommaInArguments)


[convention] 50-50: Avoid comma after the last parameter of a method call.

(Style/TrailingCommaInArguments)

🔇 Additional comments (29)
samples/example_expo/components/ui/TabBarBackground.ios.tsx (2)

1-3: LGTM! Clean and appropriate imports.

The imports are well-organized and appropriate for an iOS-specific tab bar background component using Expo's blur functionality.


5-15: Well-implemented blur background component.

The BlurTabBarBackground component correctly uses systemChromeMaterial tint for iOS system integration and appropriate absolute positioning. The comments clearly explain the system adaptation behavior.

README.md (1)

28-32: LGTM! Clear Expo installation instructions.

The addition of Expo-specific installation instructions is helpful and follows best practices.

samples/example_expo/ios/exampleexpo/AppDelegate.swift (2)

1-53: LGTM! Well-structured Expo AppDelegate implementation.

The implementation correctly follows Expo and React Native patterns:

  • Proper inheritance from ExpoAppDelegate
  • Correct React Native factory initialization
  • Appropriate deep linking support for both URL schemes and Universal Links
  • Good separation of concerns with ReactNativeDelegate

The conditional compilation for iOS/tvOS and the delegate pattern are implemented properly.


55-70: LGTM! Proper bundle URL configuration for different environments.

The ReactNativeDelegate correctly handles bundle URL resolution for development vs production environments, which is essential for Expo development workflow.

samples/example_expo/README.md (1)

1-54: LGTM! Clear and comprehensive Expo example README.

The README provides excellent guidance for users with:

  • Clear step-by-step setup instructions
  • Important compatibility notes about Expo Go limitations
  • Proper explanation of file-based routing
  • Helpful reset functionality for development
  • Standard community resources

The note about plugin incompatibility with Expo Go is particularly valuable for preventing user confusion.

samples/example_expo/android/build.gradle (1)

8-9: Verify the security and availability of custom Maven repositories.

The custom Reclaim SDK repository endpoints should be verified for:

  1. HTTPS usage for security
  2. Repository availability and reliability
  3. Authentication requirements if any

Please verify these repository endpoints are accessible and secure:

#!/bin/bash
# Description: Verify Maven repository endpoints are accessible
echo "Checking Reclaim SDK repository..."
curl -I https://reclaim-inapp-sdk.s3.ap-south-1.amazonaws.com/android/repo

echo "Checking Flutter storage repository..."
curl -I https://storage.googleapis.com/download.flutter.io

Also applies to: 36-37

samples/example_expo/android/settings.gradle (1)

1-40: LGTM: Standard Expo Android Gradle configuration

The Gradle settings file follows Expo and React Native best practices with proper plugin management, autolinking configuration, and conditional environment-based setup. The dynamic path resolution using Node.js commands is the recommended approach for these frameworks.

samples/example_expo/scripts/reset-project.js (1)

48-99: LGTM: Well-structured reset script with good error handling

The script properly handles user interaction, file system operations, and error cases. The async/await pattern is correctly implemented, and the file operations use safe methods with proper error handling.

samples/example_expo/android/app/src/main/AndroidManifest.xml (2)

2-6: Review permission usage

The manifest requests several sensitive permissions. Ensure these are actually needed:

  • WRITE_EXTERNAL_STORAGE is often unnecessary in modern Android apps (API 29+)
  • SYSTEM_ALERT_WINDOW is a sensitive permission that requires user approval

Consider removing unused permissions or documenting their necessity.


30-30: Verify ReclaimActivity configuration

The ReclaimActivity configuration looks appropriate for the Reclaim protocol integration, with proper theme and configuration change handling.

samples/example_expo/components/ParallaxScrollView.tsx (2)

49-66: LGTM: Well-implemented parallax scroll component

The component properly implements a parallax scrolling effect with good animation performance using React Native Reanimated. The animation interpolation values create a smooth parallax effect, and the component integrates well with the theming system.


52-53: Fix formatting for scroll view props

Apply the formatting fix suggested by ESLint:

        scrollEventThrottle={16}
-        scrollIndicatorInsets={{ bottom }}
-        contentContainerStyle={{ paddingBottom: bottom }}>
+        scrollIndicatorInsets={{ bottom }}
+        contentContainerStyle={{ paddingBottom: bottom }}
+      >
samples/example_expo/ios/exampleexpo.xcodeproj/project.pbxproj (1)

1-579: LGTM!

The Xcode project configuration is properly set up with correct build phases, framework references, and ReclaimInAppSdk integration.

samples/example_expo/android/gradlew (1)

1-251: LGTM!

Standard Gradle wrapper script with no modifications.

samples/example_expo/android/app/src/main/java/org/example/expo/MainActivity.kt (1)

23-23: Pass savedInstanceState to super.onCreate().

Passing null instead of savedInstanceState breaks Android's state restoration mechanism, which could cause issues when the app is restored from background or after configuration changes.

-    super.onCreate(null)
+    super.onCreate(savedInstanceState)

Likely an incorrect or invalid review comment.

samples/example_expo/android/app/src/main/java/org/example/expo/MainApplication.kt (5)

1-17: LGTM! Proper imports and package structure.

The package structure and imports are correctly configured for an Expo React Native Android application. All necessary React Native, Expo, and Android imports are included.


19-38: LGTM! Correct ReactNativeHost configuration for Expo.

The ReactNativeHost setup follows Expo best practices:

  • Uses ReactNativeHostWrapper for Expo integration
  • Properly configures packages with PackageList
  • Sets correct JS main module path for Expo (.expo/.virtual-metro-entry)
  • Correctly uses BuildConfig flags for architecture and debugging support

40-41: LGTM! Proper ReactHost implementation.

The ReactHost property correctly delegates to ReactNativeHostWrapper's createReactHost method with proper context and host parameters.


43-51: LGTM! Proper application initialization.

The onCreate method correctly:

  • Calls super.onCreate()
  • Initializes SoLoader with OpenSourceMergedSoMapping
  • Conditionally loads new architecture entry point
  • Dispatches application lifecycle events to Expo

53-56: LGTM! Proper configuration change handling.

The onConfigurationChanged method correctly forwards configuration changes to both the parent class and Expo's ApplicationLifecycleDispatcher.

samples/example_expo/android/app/build.gradle (8)

1-5: LGTM! Proper plugin configuration.

The plugin applications are correct for an Expo React Native Android app, including the necessary Android, Kotlin, and React Native plugins. The project root definition is properly configured.


20-21: LGTM! Correct Expo CLI configuration.

The Expo CLI configuration correctly uses @expo/cli with the export:embed bundle command, which is the proper way to bundle Expo apps for production.


69-82: LGTM! Proper build optimization configuration.

The Proguard and JSC flavor configurations are correctly set up:

  • Proguard is conditionally enabled via properties
  • Uses the community JSC build with a reasonable version

133-148: LGTM! Dynamic packaging options configuration.

The dynamic packaging options configuration is well-implemented with proper error handling and logging. The loop correctly processes gradle properties and applies them to packaging options.


154-171: LGTM! Conditional Fresco dependencies.

The conditional inclusion of Fresco dependencies based on image format support (GIF, WebP) is correctly implemented and follows Expo best practices for optimizing bundle size.


172-176: LGTM! Proper JavaScript engine configuration.

The conditional dependency on Hermes vs JSC is correctly implemented, allowing for flexible JavaScript engine selection based on project configuration.


12-15: Verify Node.js command execution security.

The dynamic path resolution using Node.js commands could potentially be a security risk if the environment is compromised. However, this is standard practice for Expo/React Native builds and the commands are deterministic.

#!/bin/bash
# Description: Check if there are any security best practices documentation for Node.js command execution in Gradle builds

# Search for any existing security documentation or patterns
rg -A 5 -B 5 "execute.*node" --type gradle

98-105: Security concern: Debug keystore configuration.

The debug keystore configuration uses default credentials which is acceptable for development but should never be used in production.

#!/bin/bash
# Description: Check if there are any production keystore configurations or warnings

# Look for any keystore-related configurations or documentation
rg -A 10 -B 5 "keystore|signing" --type gradle

duration: Snackbar.LENGTH_LONG,
});
break;
case ReclaimVerification.ExceptionType.Failed:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove redundant case clause.

The Failed case is redundant since it falls through to the default case which handles the same logic.

-                case ReclaimVerification.ExceptionType.Failed:
                 default:
                     Snackbar.show({
                         text: 'Verification failed',
                         duration: Snackbar.LENGTH_LONG,
                     });

Also applies to: 113-113

🧰 Tools
🪛 Biome (1.9.4)

[error] 60-60: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)

🪛 ESLint

[error] 60-60: Delete ··········

(prettier/prettier)

🤖 Prompt for AI Agents
In samples/example_expo/app/(home)/_layout.tsx at lines 60 and 113, remove the
redundant case clause for ReclaimVerification.ExceptionType.Failed since it
falls through to the default case which already handles the same logic. Simply
delete these case lines to avoid duplication and keep the switch statement
clean.

Comment on lines +40 to +72
if (error instanceof ReclaimVerification.ReclaimVerificationException) {
switch (error.type) {
case ReclaimVerification.ExceptionType.Cancelled:
Snackbar.show({
text: 'Verification cancelled',
duration: Snackbar.LENGTH_LONG,
});
break;
case ReclaimVerification.ExceptionType.Dismissed:
Snackbar.show({
text: 'Verification dismissed',
duration: Snackbar.LENGTH_LONG,
});
break;
case ReclaimVerification.ExceptionType.SessionExpired:
Snackbar.show({
text: 'Verification session expired',
duration: Snackbar.LENGTH_LONG,
});
break;
case ReclaimVerification.ExceptionType.Failed:
default:
Snackbar.show({
text: 'Verification failed',
duration: Snackbar.LENGTH_LONG,
});
}
} else {
Snackbar.show({
text: error instanceof Error ? error.message : 'An unknown verification error occurred',
duration: Snackbar.LENGTH_LONG,
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract duplicate error handling logic.

The error handling code is duplicated between handleStartVerification and handleStartVerificationFromUrl. This violates the DRY principle and makes maintenance harder.

Consider extracting the error handling into a reusable function:

+    const handleVerificationError = (error: unknown) => {
+        console.info({
+            verificationError: error,
+        });
+        if (error instanceof ReclaimVerification.ReclaimVerificationException) {
+            switch (error.type) {
+                case ReclaimVerification.ExceptionType.Cancelled:
+                    Snackbar.show({
+                        text: 'Verification cancelled',
+                        duration: Snackbar.LENGTH_LONG,
+                    });
+                    break;
+                case ReclaimVerification.ExceptionType.Dismissed:
+                    Snackbar.show({
+                        text: 'Verification dismissed',
+                        duration: Snackbar.LENGTH_LONG,
+                    });
+                    break;
+                case ReclaimVerification.ExceptionType.SessionExpired:
+                    Snackbar.show({
+                        text: 'Verification session expired',
+                        duration: Snackbar.LENGTH_LONG,
+                    });
+                    break;
+                case ReclaimVerification.ExceptionType.Failed:
+                default:
+                    Snackbar.show({
+                        text: 'Verification failed',
+                        duration: Snackbar.LENGTH_LONG,
+                    });
+            }
+        } else {
+            Snackbar.show({
+                text: error instanceof Error ? error.message : 'An unknown verification error occurred',
+                duration: Snackbar.LENGTH_LONG,
+            });
+        }
+    };

     } catch (error) {
-        console.info({
-            verificationError: error,
-        });
-        if (error instanceof ReclaimVerification.ReclaimVerificationException) {
-            // ... duplicate error handling code ...
-        } else {
-            // ... duplicate error handling code ...
-        }
+        handleVerificationError(error);
     }

Also applies to: 93-125

🧰 Tools
🪛 Biome (1.9.4)

[error] 60-60: Useless case clause.

because the default clause is present:

Unsafe fix: Remove the useless case.

(lint/complexity/noUselessSwitchCase)

🪛 ESLint

[error] 40-40: Delete ······

(prettier/prettier)


[error] 41-41: Replace ················ with ········

(prettier/prettier)


[error] 42-42: Delete ··········

(prettier/prettier)


[error] 43-43: Replace ························ with ············

(prettier/prettier)


[error] 44-44: Replace ···························· with ··············

(prettier/prettier)


[error] 45-45: Replace ···························· with ··············

(prettier/prettier)


[error] 46-46: Replace ························ with ············

(prettier/prettier)


[error] 47-47: Replace ························ with ············

(prettier/prettier)


[error] 48-48: Delete ··········

(prettier/prettier)


[error] 49-49: Replace ························ with ············

(prettier/prettier)


[error] 50-50: Replace ···························· with ··············

(prettier/prettier)


[error] 51-51: Delete ··············

(prettier/prettier)


[error] 52-52: Delete ············

(prettier/prettier)


[error] 53-53: Replace ························ with ············

(prettier/prettier)


[error] 54-54: Delete ··········

(prettier/prettier)


[error] 55-55: Replace ························ with ············

(prettier/prettier)


[error] 56-56: Delete ··············

(prettier/prettier)


[error] 57-57: Replace ···························· with ··············

(prettier/prettier)


[error] 58-58: Delete ············

(prettier/prettier)


[error] 59-59: Replace ························ with ············

(prettier/prettier)


[error] 60-60: Delete ··········

(prettier/prettier)


[error] 61-61: Delete ··········

(prettier/prettier)


[error] 62-62: Replace ························ with ············

(prettier/prettier)


[error] 63-63: Delete ··············

(prettier/prettier)


[error] 64-64: Replace ···························· with ··············

(prettier/prettier)


[error] 65-65: Replace ························ with ············

(prettier/prettier)


[error] 66-66: Replace ················ with ········

(prettier/prettier)


[error] 67-67: Replace ············ with ······

(prettier/prettier)


[error] 68-68: Delete ········

(prettier/prettier)


[error] 69-69: Replace ··········text:·error·instanceof·Error·?·error.message with text:⏎············error·instanceof·Error⏎··············?·error.message⏎·············

(prettier/prettier)


[error] 70-70: Replace ···················· with ··········

(prettier/prettier)


[error] 71-71: Delete ········

(prettier/prettier)


[error] 72-72: Replace ············ with ······

(prettier/prettier)

🤖 Prompt for AI Agents
In samples/example_expo/app/(home)/_layout.tsx between lines 40-72 and 93-125,
the error handling logic for ReclaimVerification exceptions is duplicated.
Extract this repeated error handling code into a separate reusable function that
accepts the error object and shows the appropriate Snackbar message. Replace the
duplicated blocks in both handleStartVerification and
handleStartVerificationFromUrl with calls to this new function to adhere to the
DRY principle and improve maintainability.

Comment on lines +26 to +27
console.assert(config.REACT_APP_RECLAIM_APP_ID, 'RECLAIM_APP_ID is not set');
console.assert(config.REACT_APP_RECLAIM_APP_SECRET, 'RECLAIM_APP_SECRET is not set');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace console.assert with proper error handling.

console.assert doesn't throw errors in production builds and won't prevent execution if environment variables are missing. This could lead to runtime errors when the SDK is initialized with empty strings.

-        console.assert(config.REACT_APP_RECLAIM_APP_ID, 'RECLAIM_APP_ID is not set');
-        console.assert(config.REACT_APP_RECLAIM_APP_SECRET, 'RECLAIM_APP_SECRET is not set');
+        if (!config.REACT_APP_RECLAIM_APP_ID || !config.REACT_APP_RECLAIM_APP_SECRET) {
+            Snackbar.show({
+                text: 'Reclaim app credentials are not configured',
+                duration: Snackbar.LENGTH_LONG,
+            });
+            return;
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.assert(config.REACT_APP_RECLAIM_APP_ID, 'RECLAIM_APP_ID is not set');
console.assert(config.REACT_APP_RECLAIM_APP_SECRET, 'RECLAIM_APP_SECRET is not set');
if (!config.REACT_APP_RECLAIM_APP_ID || !config.REACT_APP_RECLAIM_APP_SECRET) {
Snackbar.show({
text: 'Reclaim app credentials are not configured',
duration: Snackbar.LENGTH_LONG,
});
return;
}
🧰 Tools
🪛 ESLint

[error] 26-26: Replace ····console.assert(config.REACT_APP_RECLAIM_APP_ID,·'RECLAIM_APP_ID·is·not·set'); with console.assert(⏎······config.REACT_APP_RECLAIM_APP_ID,⏎······'RECLAIM_APP_ID·is·not·set'

(prettier/prettier)


[error] 27-27: Replace ····console.assert(config.REACT_APP_RECLAIM_APP_SECRET,·'RECLAIM_APP_SECRET·is·not·set'); with );⏎····console.assert(⏎······config.REACT_APP_RECLAIM_APP_SECRET,⏎······'RECLAIM_APP_SECRET·is·not·set'

(prettier/prettier)

🤖 Prompt for AI Agents
In samples/example_expo/app/(home)/_layout.tsx around lines 26 to 27, replace
the console.assert statements checking for REACT_APP_RECLAIM_APP_ID and
REACT_APP_RECLAIM_APP_SECRET with proper error handling that throws an error if
these environment variables are missing. This ensures the application halts
execution and clearly notifies the developer of the missing configuration
instead of silently failing in production.

require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")

require 'json'
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve error handling for JSON parsing.

Using rescue {} silently ignores all errors when reading the configuration file, which could hide important issues like missing files or syntax errors.

-podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
+begin
+  podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json')))
+rescue Errno::ENOENT
+  puts "Warning: Podfile.properties.json not found, using defaults"
+  podfile_properties = {}
+rescue JSON::ParserError => e
+  raise "Error parsing Podfile.properties.json: #{e.message}"
+end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
begin
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json')))
rescue Errno::ENOENT
puts "Warning: Podfile.properties.json not found, using defaults"
podfile_properties = {}
rescue JSON::ParserError => e
raise "Error parsing Podfile.properties.json: #{e.message}"
end
🧰 Tools
🪛 RuboCop (1.75.5)

[convention] 5-5: Avoid using rescue in its modifier form.

(Style/RescueModifier)

🤖 Prompt for AI Agents
In samples/example_expo/ios/Podfile at line 5, the current use of `rescue {}`
silently ignores all errors during JSON parsing, which can hide critical issues.
Replace the generic rescue with explicit error handling that catches specific
exceptions like file not found or JSON parse errors, and log or raise a
meaningful error message to inform about the problem instead of silently
ignoring it.

Comment on lines +110 to +118
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Security warning: Production uses debug signing config.

The release build type is configured to use the debug signing config, which is not suitable for production. The comment acknowledges this, but it's important to ensure proper keystore generation before production deployment.

For production, you should:

  1. Generate a proper release keystore
  2. Configure signing with production credentials
  3. Store sensitive signing information securely (e.g., environment variables)
         release {
-            // Caution! In production, you need to generate your own keystore file.
-            // see https://reactnative.dev/docs/signed-apk-android.
-            signingConfig signingConfigs.debug
+            signingConfig signingConfigs.release // Configure proper release signing
             shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
             minifyEnabled enableProguardInReleaseBuilds
             proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
             crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
release {
signingConfig signingConfigs.release // Configure proper release signing
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
🤖 Prompt for AI Agents
In samples/example_expo/android/app/build.gradle around lines 110 to 118, the
release build is incorrectly using the debug signing configuration, which is
insecure for production. To fix this, generate a proper release keystore,
configure the signingConfigs block with the release keystore credentials, and
update the release build type to use this release signingConfig instead of
debug. Ensure sensitive keystore passwords and aliases are stored securely, such
as in environment variables or gradle.properties, and referenced appropriately
in the build.gradle file.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
README.md (4)

52-53: Comma missing after introductory phrase

A comma after “To do so” improves readability and resolves the LanguageTool warning.

-Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so merge the following code to the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:
+Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so, merge the following code into the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:

80-88: Add language identifier to fenced code block

markdownlint flags this block (MD040). Prefix it with sh (or bash) for proper syntax highlighting.

-```
+# For iOS / Android build commands
+```sh
# For iOS
npx expo prebuild
npx expo run:ios

# For Android
npx expo prebuild
npx expo run:android

92-98: Second fenced block also lacks a language spec

Same markdownlint issue as above. Add sh.

-```
+# For EAS build commands
+```sh
# For online builds
npx eas-cli build --profile development

# For local builds
npx eas-cli build --profile development --local

100-100: Fix typo “physicial” → “physical”

-Follow [the fixing ios performance issues guide](#fixing-performance-issues-on-ios-physical-devices) to fix slow proof generation on iOS physicial devices.
+Follow [the fixing iOS performance issues guide](#fixing-performance-issues-on-ios-physical-devices) to fix slow proof generation on iOS physical devices.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5fb22e and 1daf9ce.

📒 Files selected for processing (1)
  • README.md (2 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~52-~52: Possible missing comma found.
Context: ... the Reclaim InApp Config Plugin. To do so merge the following code to the plugins...

(AI_HYDRA_LEO_MISSING_COMMA)

🪛 markdownlint-cli2 (0.17.2)
README.md

80-80: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


92-92: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
README.md (1)

25-31: Streamline the “Installation” sub-section formatting

The two alternative guides are currently rendered as bold paragraphs. Using a short unordered list improves scannability and keeps the visual rhythm consistent with the surrounding documentation sections.

-**For React Native projects without Expo:**
-📖 [Installation Guide for React Native (No Framework)](documentation/install-no-framework.md)
-
-**For React Native Expo projects:**
-📖 [Installation Guide for React Native Expo](documentation/install-expo.md)
+• **React-Native (no Expo):**  
+  📖 [Installation Guide](documentation/install-no-framework.md)
+
+• **React-Native + Expo:**  
+  📖 [Installation Guide](documentation/install-expo.md)
documentation/install-expo.md (3)

22-24: Add missing comma and use “into” for clarity

Current sentence reads a little abruptly and may trip non-native readers.

-Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so merge the following code to the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:
+Expo users can skip the native configuration changes by adding the Reclaim InApp Config Plugin. To do so, merge the following code into the plugins section of your `app.json`, `app.config.js`, or `app.config.ts` file:

46-58: Specify a shell language marker for fenced blocks

markdownlint (MD040) warns when the language is omitted. Adding sh (or bash) silences the warning and enables proper syntax highlighting.

-```
+# For iOS / Android
+```sh
# For iOS
npx expo prebuild
npx expo run:ios
...
npx expo run:android
Apply the same change to the EAS-build command block below (lines 63-68).

---

`70-92`: **Tighten wording and add missing article**  

Minor grammar fixes and reduction of repetitive “Click on …” phrasing.

```diff
-Your app performance will be severely impacted when you run debug executable on a physical device. Fixing this requires a simple change in your Xcode project xcscheme.
+Your app’s performance drops noticeably when you run the debug executable on a physical device. You can resolve this with a small change in your Xcode scheme.
...
-4. Click on the **Edit Scheme** button.
-5. Click on the **Run** tab.
-6. Click on the **Arguments** tab and check the **Environment Variables** section.
+4. Select **Edit Scheme**.
+5. Open the **Run** tab.
+6. Switch to **Arguments** and locate **Environment Variables**.
documentation/install-no-framework.md (3)

105-107: Insert the definite article for smoother reading

-Your app performance will be severely impacted when you run debug executable on a physical device.
+Your app’s performance will be severely impacted when you run the debug executable on a physical device.

90-94: Provide language identifier for the Podfile snippet

markdownlint flags this fenced block. Adding ruby keeps lint happy and renders syntax highlighting.

-```
+```ruby
platform :ios, '13.0' # or platform :ios, min_ios_version_supported
Repeat for other Ruby/Groovy snippets that currently lack a language tag.

---

`130-130`: **Remove trailing colon in heading**  

The colon violates MD026 and is unnecessary.

```diff
-#### Overriding SDK dependency in `Podfile` (Optional):
+#### Overriding SDK dependency in `Podfile` (Optional)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dc0e4e and c5657d3.

📒 Files selected for processing (3)
  • README.md (1 hunks)
  • documentation/install-expo.md (1 hunks)
  • documentation/install-no-framework.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
documentation/install-expo.md

[uncategorized] ~22-~22: A comma might be missing here.
Context: ... the Reclaim InApp Config Plugin. To do so merge the following code to the plugins...

(AI_EN_LECTOR_MISSING_PUNCTUATION_COMMA)


[uncategorized] ~72-~72: Possible missing article found.
Context: ... will be severely impacted when you run debug executable on a physical device. Fixing...

(AI_HYDRA_LEO_MISSING_THE)


[style] ~81-~81: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent xcscheme in Xcode" width="500"> 4. Click on the Edit Scheme button. 5. Click...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~82-~82: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Click on the Edit Scheme button. 5. Click on the Run tab. 6. Click on the **A...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~83-~83: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...button. 5. Click on the Run tab. 6. Click on the Arguments tab and check the ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[uncategorized] ~92-~92: Possible missing comma found.
Context: .... 9. Run the app on a physical device. Now your React Native Expo project is ready...

(AI_HYDRA_LEO_MISSING_COMMA)

documentation/install-no-framework.md

[uncategorized] ~105-~105: Possible missing article found.
Context: ... will be severely impacted when you run debug executable on a physical device. Fixing...

(AI_HYDRA_LEO_MISSING_THE)


[style] ~114-~114: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent xcscheme in Xcode" width="500"> 4. Click on the Edit Scheme button. 5. Click...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~115-~115: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Click on the Edit Scheme button. 5. Click on the Run tab. 6. Click on the **A...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~116-~116: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...button. 5. Click on the Run tab. 6. Click on the Arguments tab and check the ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[uncategorized] ~125-~125: Possible missing comma found.
Context: .... 9. Run the app on a physical device. Now your React Native project is ready to u...

(AI_HYDRA_LEO_MISSING_COMMA)

🪛 markdownlint-cli2 (0.17.2)
documentation/install-no-framework.md

90-90: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


130-130: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (1)
documentation/install-expo.md (1)

28-33: Double-check plugin resolution path

The example lists the plugin as:

"plugins": [
  "@reclaimprotocol/inapp-rn-sdk",
  
]

This assumes the package’s package.json exposes the config plugin via the "expo" or "main" entry field. If the plugin lives under expo-plugin/dist (as the directory structure suggests) make sure package.json contains

"expo": "./expo-plugin/dist/index.js"

so that Expo can resolve it without an explicit sub-path.

Mushaheed Syed added 2 commits June 27, 2025 14:47
@predatorx7 predatorx7 merged commit 22e1cd9 into main Jun 27, 2025
@predatorx7 predatorx7 deleted the mushaheed.expo_setup branch June 27, 2025 09:20
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (10)
samples/example_expo/README.md (4)

5-5: Use “incompatible” for conciseness

not compatibleincompatible keeps the sentence tight and avoids the double-negative style.

-**Note:** This plugin is not compatible with Expo Go.
+**Note:** This plugin is incompatible with Expo Go.

23-24: Fix article before “Android emulator”

Grammatically, it should be “an Android emulator.”

-...open the app in a Android emulator...
+...open the app in an Android emulator...

11-15: Offer Yarn parity for dependency install

You later provide Yarn commands (yarn android / yarn ios) but step 2 only shows npm install. Add the Yarn equivalent for consistency.

    npm install
+   # OR
+   yarn install

39-45: Clarify CocoaPods step wording

“This only needs to be run on first clone” → “the first clone” and capitalise SDK name.

-For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating inapp sdk).
+For iOS, remember to install CocoaPods dependencies (this only needs to be run on the first clone or after updating the InApp SDK).
documentation/install-expo.md (3)

22-22: Insert comma after introductory clause

Missing comma after “To do so”.

-To do so merge the following code
+To do so, merge the following code

46-46: Minor wording & casing

“Expo Go” is fine; drop all-caps NOT and fix punctuation.

-Note: This module contains custom native code which is NOT supported by Expo Go
+Note: This module contains custom native code that is not supported by Expo Go.

70-72: iOS spelling & missing article

IOSiOS; insert a before “debug executable”.

-#### Fixing performance issues on IOS physical devices
-Your app performance will be severely impacted when you run debug executable on a physical device.
+#### Fixing performance issues on iOS physical devices
+Your app performance will be severely impacted when you run a debug executable on a physical device.
documentation/install-no-framework.md (3)

70-72: Capitalise “Alternatively” and tighten wording

-or alternatively add the following repositories to the relevant repositories block:
+Alternatively, add the following repositories to the relevant repositories block:

103-106: iOS casing and missing article

-#### Fixing performance issues on IOS physical devices
-Your app performance will be severely impacted when you run debug executable on a physical device.
+#### Fixing performance issues on iOS physical devices
+Your app performance will be severely impacted when you run a debug executable on a physical device.

38-49: Manifest snippet indentation

Many React Native projects indent XML with two spaces; your snippet is indented six, which may confuse copy-paste users. Consider normalising to two.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5657d3 and 6fad1b1.

📒 Files selected for processing (4)
  • documentation/install-expo.md (1 hunks)
  • documentation/install-no-framework.md (1 hunks)
  • samples/example_expo/README.md (1 hunks)
  • samples/example_expo/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • samples/example_expo/package.json
🧰 Additional context used
🪛 LanguageTool
documentation/install-expo.md

[uncategorized] ~22-~22: Possible missing comma found.
Context: ... the Reclaim InApp Config Plugin. To do so merge the following code to the plugins...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~72-~72: Possible missing article found.
Context: ... will be severely impacted when you run debug executable on a physical device. Fixing...

(AI_HYDRA_LEO_MISSING_THE)


[style] ~81-~81: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent xcscheme in Xcode" width="500"> 4. Click on the Edit Scheme button. 5. Click...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~82-~82: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Click on the Edit Scheme button. 5. Click on the Run tab. 6. Click on the **A...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~83-~83: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...button. 5. Click on the Run tab. 6. Click on the Arguments tab and check the ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[uncategorized] ~92-~92: Possible missing comma found.
Context: .... 9. Run the app on a physical device. Now your React Native Expo project is ready...

(AI_HYDRA_LEO_MISSING_COMMA)

documentation/install-no-framework.md

[uncategorized] ~105-~105: Possible missing article found.
Context: ... will be severely impacted when you run debug executable on a physical device. Fixing...

(AI_HYDRA_LEO_MISSING_THE)


[style] ~114-~114: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent xcscheme in Xcode" width="500"> 4. Click on the Edit Scheme button. 5. Click...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~115-~115: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...Click on the Edit Scheme button. 5. Click on the Run tab. 6. Click on the **A...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~116-~116: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...button. 5. Click on the Run tab. 6. Click on the Arguments tab and check the ...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[uncategorized] ~125-~125: Possible missing comma found.
Context: .... 9. Run the app on a physical device. Now your React Native project is ready to u...

(AI_HYDRA_LEO_MISSING_COMMA)

samples/example_expo/README.md

[style] ~5-~5: Consider using “incompatible” to avoid wordiness.
Context: ...te-expo-app). Note: This plugin is not compatible with Expo Go. Please use a development ...

(NOT_ABLE_PREMIUM)


[uncategorized] ~74-~74: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...https://github.com/expo/expo): View our open source platform and contribute. - [Discord com...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🔇 Additional comments (1)
documentation/install-expo.md (1)

28-33: ```shell
#!/bin/bash

Check the package name in package.json

echo "Package name in package.json:"
grep -E '^\s*"name":' -m1 -n package.json

Verify that the built plugin entrypoint exists

echo ""
echo "Looking for expo-plugin/build/index.js:"
fd --max-depth 3 "expo-plugin/build/index.js"


</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants