RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-04-08Advanced

Rork Max + EAS Build Custom Native Module Errors: Complete Fix Guide

Comprehensive guide to fixing EAS Build errors when adding custom native modules to Rork Max apps. Covers Config Plugin creation, iOS Podfile conflicts, Android Gradle errors, Hermes compatibility, and native initialization issues.

Rork Max229EAS Build14Native Modules5Config Plugin3iOS109Android43PodfileErrors

Rork Max + EAS Build Custom Native Module Errors: Complete Fix Guide

Rork Max works great for the vast majority of apps — but when you need something outside the Expo SDK (Bluetooth hardware, custom SDKs, native camera libraries), you're in EAS Build territory with custom native modules.

The first time through, it's a maze of Podfile conflicts, Execution failed for task ':app:merge...', and "the build passes but crashes immediately at launch." This guide maps out all the major failure modes with concrete fixes.

The Foundation: How EAS Build and Config Plugins Work

To add native code to a Managed Workflow Expo project (what Rork Max uses internally), you need Config Plugins. These are Node.js scripts that modify the native iOS and Android project files during npx expo prebuild — which EAS Build runs automatically before compiling.

Many libraries ship their own Config Plugin (like @config-plugins/react-native-ble-plx). For libraries that don't, you'll need to write one.

app.config.js plugins array
    ↓
npx expo prebuild (runs automatically in EAS Build)
    ↓
ios/ and android/ directories are generated
    ↓
iOS: pod install → Xcode build
Android: Gradle build
    ↓
Binary output

Error #1: Podfile Version Conflicts

Symptom: EAS Build fails with:

[!] CocoaPods could not find compatible versions for pod "SomeLibrary":
  In snapshot (Podfile.lock):
    SomeLibrary (= 1.2.0)
  In Podfile:
    SomeLibrary (~> 2.0)
// config-plugins/force-pod-version.js
const { withPodfile } = require('@expo/config-plugins');
 
module.exports = (config) => {
  return withPodfile(config, (modConfig) => {
    const { modResults } = modConfig;
    
    modResults.contents = modResults.contents.replace(
      /# Add any custom podfile content here/,
      `# Add any custom podfile content here
# Force version to resolve dependency conflict
pod 'SomeLibrary', '~> 2.0.0'`
    );
    
    return modConfig;
  });
};
// app.config.js
export default {
  expo: {
    plugins: ['./config-plugins/force-pod-version']
  }
};

Resetting the Podfile.lock:

npx expo prebuild --clean       # regenerate ios/ and android/ from scratch
cd ios && rm Podfile.lock       # remove the lock file
pod install --repo-update       # reinstall with updated pod specs
cd ..

Error #2: Config Plugin Not Applied — Module Crashes at Runtime

Symptom: Build succeeds, but app crashes with Native module cannot be null or Cannot read property of undefined.

This means the Config Plugin didn't write the native initialization code into the project. Verify your app.config.js plugins array:

export default {
  expo: {
    plugins: [
      // Wrong: library may not have a config plugin under this name
      'react-native-ble-plx',
      
      // Correct: check for @config-plugins namespace
      '@config-plugins/react-native-ble-plx',
      
      // Correct with options: pass config as array second element
      ['@config-plugins/react-native-ble-plx', {
        bluetoothAlwaysPermission: "$(PRODUCT_NAME) uses Bluetooth to connect to devices",
        bluetoothPeripheralPermission: "$(PRODUCT_NAME) uses Bluetooth to connect to peripheral devices"
      }],
    ]
  }
};

Verify Config Plugin application before building:

# Run prebuild to generate native files locally
npx expo prebuild --clean
 
# Check if iOS permissions were added
cat ios/MyApp/Info.plist | grep -A 2 "NSBluetooth"
 
# Check if Android permissions were added
cat android/app/src/main/AndroidManifest.xml | grep "BLUETOOTH"
 
# If these entries are missing, the Config Plugin didn't apply correctly

Error #3: Android Gradle Build Failures

Symptom: iOS builds fine but Android fails with errors like Execution failed for task ':app:mergeReleaseJavaResource' or Manifest merger failed.

// config-plugins/fix-android-build.js
 
const { withAppBuildGradle, withProjectBuildGradle } = require('@expo/config-plugins');
 
// Fix minSdkVersion when a library requires a higher minimum
const fixMinSdkVersion = (config) => {
  return withAppBuildGradle(config, (modConfig) => {
    modConfig.modResults.contents = modConfig.modResults.contents.replace(
      /minSdkVersion = \d+/,
      'minSdkVersion = 24'
    );
    return modConfig;
  });
};
 
// Fix Kotlin version conflicts
const fixKotlinVersion = (config) => {
  return withProjectBuildGradle(config, (modConfig) => {
    modConfig.modResults.contents = modConfig.modResults.contents.replace(
      /kotlinVersion = '.*'/,
      "kotlinVersion = '1.9.0'"
    );
    return modConfig;
  });
};
 
module.exports = (config) => {
  config = fixMinSdkVersion(config);
  config = fixKotlinVersion(config);
  return config;
};
// app.config.js
export default {
  expo: {
    plugins: ['./config-plugins/fix-android-build']
  }
};

Error #4: Hermes and New Architecture Incompatibility

Symptom: Module works in Expo Go (uses JSC) but crashes with Hermes, or Calling synchronous methods on native modules is not supported.

// app.config.js — control Hermes and New Architecture settings
export default {
  expo: {
    jsEngine: "hermes",   // default, keep this
    
    // If a module is incompatible with New Architecture, disable it here
    // (this is a temporary measure — prefer updating the library)
    newArchEnabled: false,
    
    ios: {
      newArchEnabled: false,
    },
    android: {
      newArchEnabled: false,
    }
  }
};

To check if a specific library supports Hermes and New Architecture, look for a react-native.config.js or check the library's GitHub issues for "Hermes" or "New Architecture" mentions.

Error #5: Missing Native Initialization Code

Symptom: Module is installed and Config Plugin exists, but at runtime you still get "module not found" errors.

Older React Native libraries that predate Config Plugins sometimes require manual entries in MainApplication.java (Android) and AppDelegate.mm (iOS). Config Plugins let you automate this:

// config-plugins/add-native-init.js
const { withMainApplication, withAppDelegate } = require('@expo/config-plugins');
 
// Android: add module to MainApplication.java
const withAndroidModule = (config) => {
  return withMainApplication(config, (modConfig) => {
    const { modResults } = modConfig;
    
    if (!modResults.contents.includes('import com.example.CustomModule;')) {
      // Add import
      modResults.contents = modResults.contents.replace(
        'import com.facebook.react.ReactApplication;',
        `import com.facebook.react.ReactApplication;
import com.example.CustomModule;`
      );
      
      // Add to packages list
      modResults.contents = modResults.contents.replace(
        'packages.add(new MainReactPackage());',
        `packages.add(new MainReactPackage());
packages.add(new CustomModule());`
      );
    }
    
    return modConfig;
  });
};
 
// iOS: add initialization to AppDelegate.mm
const withIOSInit = (config) => {
  return withAppDelegate(config, (modConfig) => {
    const { modResults } = modConfig;
    
    if (!modResults.contents.includes('#import <CustomSDK/CustomSDK.h>')) {
      modResults.contents = modResults.contents.replace(
        '#import <React/RCTBridge.h>',
        `#import <React/RCTBridge.h>
#import <CustomSDK/CustomSDK.h>`
      );
    }
    
    return modConfig;
  });
};
 
module.exports = (config) => {
  config = withAndroidModule(config);
  config = withIOSInit(config);
  return config;
};

Efficient Debug Strategy for EAS Build

EAS Build cycles are expensive (10–15 minutes per build). Minimize them with local verification first:

# Step 1: Verify prebuild output before EAS Build
npx expo prebuild --clean
# Inspect ios/ and android/ — check all expected changes are present
 
# Step 2: Test a local release build (requires macOS + Xcode for iOS)
npx expo run:ios --configuration Release
# or
npx expo run:android --variant release
 
# Step 3: Only after local validation, submit to EAS Build
eas build --profile preview --platform ios
 
# View build logs
eas build:list
eas build:view [BUILD_ID]

Multi-profile eas.json design:

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": { "buildConfiguration": "Debug" }
    },
    "preview": {
      "distribution": "internal",
      "ios": { "buildConfiguration": "Release" },
      "env": { "API_URL": "https://staging.example.com" },
      "cache": {
        "key": "preview-cache-v1"
      }
    },
    "production": {
      "distribution": "store",
      "ios": { "buildConfiguration": "Release" },
      "env": { "API_URL": "https://api.example.com" }
    }
  }
}

Managing secrets securely:

# Store sensitive values as EAS Secrets (never commit these to git)
eas secret:create --scope project --name STRIPE_SECRET_KEY --value "sk_live_xxxxx"
eas secret:create --scope project --name FIREBASE_SERVICE_ACCOUNT --value "$(cat service-account.json)"
 
# List configured secrets
eas secret:list

Looking back

EAS Build custom native module errors fall into five main patterns:

  • Podfile conflicts → Use withPodfile Config Plugin to pin conflicting versions
  • Config Plugin not applied → Verify with npx expo prebuild --clean, check @config-plugins/ namespace
  • Android Gradle errors → Use withAppBuildGradle / withProjectBuildGradle to patch minSdkVersion and Kotlin version
  • Hermes incompatibility → Set newArchEnabled: false as a temporary workaround while waiting for library updates
  • Missing native initialization → Write custom withMainApplication / withAppDelegate plugins

The core diagnostic practice is: always run npx expo prebuild --clean and inspect the generated native files before submitting to EAS Build. Most issues are visible in the generated files, saving you multiple 15-minute build cycles.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Dev Tools2026-05-02
Adding Native Modules to Rork-Generated Apps: A Practical Guide to Expo Prebuild
When your Rork prototype needs a native SDK or custom module, Expo Prebuild is the bridge to production. This practical guide walks through the limits of Managed Workflow and the actual commands for moving toward Bare Workflow.
Dev Tools2026-05-01
Implementing Screen Recording and Broadcast in Rork Max — A Production Guide for ReplayKit and MediaProjection
Integrate iOS ReplayKit and Android MediaProjection into your Rork Max app for gameplay recording, tutorial creation, and live broadcasting—covering the full production pipeline.
Dev Tools2026-04-25
Why Your Rork App Icon Won't Update — Cache Fixes for iOS and Android
Replaced your Rork app icon but still seeing the old one? Walk through the layered causes — iOS SpringBoard cache, EAS Build cache, missing Android adaptive icons — and the exact fixes that get the new icon to stick.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →