Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Native Module Helper

ASecurity

Create custom React Native native modules for iOS and Android. Use when integrating native SDKs, optimizing performance-critical code, or accessing platform-specific APIs. Trigger words include "native module", "bridge", "native code", "iOS bridge", "Android bridge", "Turbo Module".

29 stars
0 votes
0 copies
6 views
Added 12/21/2025
developmentjavascripttypescriptjavarubyswiftkotlinreactnodetestingapi

Works with

api

Security Analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned 2/10/2026

$npx -y skills add armanzeroeight/fastagent-plugins --skill native-module-helper --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Native Module Helper?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Native Module Helper
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/armanzeroeight-native-module-helper/badge)](https://www.skillsdirectory.com/skills/armanzeroeight-native-module-helper)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: native-module-helper
description: Create custom React Native native modules for iOS and Android. Use when integrating native SDKs, optimizing performance-critical code, or accessing platform-specific APIs. Trigger words include "native module", "bridge", "native code", "iOS bridge", "Android bridge", "Turbo Module".
---

# Native Module Helper

Build custom native modules to bridge JavaScript and native code in React Native.

## Quick Start

Native modules expose native functionality to JavaScript. Choose based on React Native version:
- **Legacy Bridge**: RN < 0.68 (stable, widely supported)
- **Turbo Modules**: RN >= 0.68 (better performance, type-safe)

## Instructions

### Step 1: Plan Module Interface

**Design JavaScript API:**
```javascript
// What you want to call from JS
import { NativeModules } from 'react-native';
const { MyModule } = NativeModules;

// Synchronous
const result = MyModule.getValue();

// Asynchronous (Promise)
const data = await MyModule.fetchData();

// With callback
MyModule.processData(input, (error, result) => {
  if (error) console.error(error);
  else console.log(result);
});

// Event emitter
MyModule.addListener('onUpdate', (event) => {
  console.log(event);
});
```

**Keep bridge calls minimal:**
- Batch operations when possible
- Avoid frequent small calls
- Use events for continuous updates

### Step 2: Create Module Structure

**File structure:**
```
MyModule/
├── ios/
│   ├── MyModule.h
│   ├── MyModule.m (or .swift)
│   └── MyModule-Bridging-Header.h (if Swift)
├── android/
│   └── src/main/java/com/mymodule/
│       ├── MyModulePackage.java
│       └── MyModule.java (or .kt)
├── js/
│   └── NativeMyModule.ts
└── package.json
```

### Step 3: Implement iOS Module

**Objective-C (.h file):**
```objc
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface MyModule : RCTEventEmitter <RCTBridgeModule>
@end
```

**Objective-C (.m file):**
```objc
#import "MyModule.h"

@implementation MyModule

RCT_EXPORT_MODULE();

// Synchronous method
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getValue)
{
  return @"value";
}

// Async with Promise
RCT_EXPORT_METHOD(fetchData:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  // Perform operation
  if (success) {
    resolve(@{@"data": result});
  } else {
    reject(@"ERROR_CODE", @"Error message", error);
  }
}

// Async with callback
RCT_EXPORT_METHOD(processData:(NSString *)input
                  callback:(RCTResponseSenderBlock)callback)
{
  // Process data
  callback(@[[NSNull null], result]); // [error, result]
}

// Event emitter
- (NSArray<NSString *> *)supportedEvents
{
  return @[@"onUpdate"];
}

- (void)sendUpdate:(NSDictionary *)data
{
  [self sendEventWithName:@"onUpdate" body:data];
}

@end
```

### Step 4: Implement Android Module

**Java module:**
```java
package com.mymodule;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.modules.core.DeviceEventManagerModule;

public class MyModule extends ReactContextBaseJavaModule {
    private ReactApplicationContext reactContext;

    public MyModule(ReactApplicationContext context) {
        super(context);
        this.reactContext = context;
    }

    @Override
    public String getName() {
        return "MyModule";
    }

    // Synchronous method
    @ReactMethod(isBlockingSynchronousMethod = true)
    public String getValue() {
        return "value";
    }

    // Async with Promise
    @ReactMethod
    public void fetchData(Promise promise) {
        try {
            WritableMap result = Arguments.createMap();
            result.putString("data", "value");
            promise.resolve(result);
        } catch (Exception e) {
            promise.reject("ERROR_CODE", "Error message", e);
        }
    }

    // Async with callback
    @ReactMethod
    public void processData(String input, Callback callback) {
        try {
            String result = process(input);
            callback.invoke(null, result); // error, result
        } catch (Exception e) {
            callback.invoke(e.getMessage(), null);
        }
    }

    // Event emitter
    private void sendEvent(String eventName, WritableMap params) {
        reactContext
            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
            .emit(eventName, params);
    }
}
```

**Package registration:**
```java
package com.mymodule;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MyModulePackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new MyModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}
```

### Step 5: Link Module

**Auto-linking (RN >= 0.60):**

Create `package.json` in module root:
```json
{
  "name": "react-native-my-module",
  "version": "1.0.0",
  "main": "js/index.js",
  "react-native": "js/index.js"
}
```

**Manual linking (if needed):**

iOS: Add to Podfile
```ruby
pod 'MyModule', :path => '../node_modules/react-native-my-module'
```

Android: Add to `settings.gradle`
```gradle
include ':react-native-my-module'
project(':react-native-my-module').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-my-module/android')
```

### Step 6: Create TypeScript Interface

```typescript
// js/NativeMyModule.ts
import { NativeModules, NativeEventEmitter } from 'react-native';

interface MyModuleInterface {
  getValue(): string;
  fetchData(): Promise<{ data: string }>;
  processData(input: string, callback: (error: string | null, result: string | null) => void): void;
  addListener(eventName: string, listener: (event: any) => void): void;
  removeListeners(count: number): void;
}

const { MyModule } = NativeModules;
const eventEmitter = new NativeEventEmitter(MyModule);

export default MyModule as MyModuleInterface;
export { eventEmitter };
```

## Common Patterns

### Threading

**iOS (run on background thread):**
```objc
RCT_EXPORT_METHOD(heavyTask:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Heavy operation
    NSString *result = [self performHeavyOperation];
    
    dispatch_async(dispatch_get_main_queue(), ^{
      resolve(result);
    });
  });
}
```

**Android (run on background thread):**
```java
@ReactMethod
public void heavyTask(Promise promise) {
    new Thread(() -> {
        try {
            String result = performHeavyOperation();
            promise.resolve(result);
        } catch (Exception e) {
            promise.reject("ERROR", e);
        }
    }).start();
}
```

### Data Type Conversion

**iOS:**
```objc
// JS -> Native
NSString *string = [RCTConvert NSString:value];
NSNumber *number = [RCTConvert NSNumber:value];
NSArray *array = [RCTConvert NSArray:value];
NSDictionary *dict = [RCTConvert NSDictionary:value];

// Native -> JS
return @{
  @"string": @"value",
  @"number": @(42),
  @"array": @[@"a", @"b"],
  @"dict": @{@"key": @"value"}
};
```

**Android:**
```java
// JS -> Native (automatic)
String string = input;
int number = input;
ReadableArray array = input;
ReadableMap map = input;

// Native -> JS
WritableMap result = Arguments.createMap();
result.putString("string", "value");
result.putInt("number", 42);

WritableArray array = Arguments.createArray();
array.pushString("a");
array.pushString("b");
result.putArray("array", array);
```

### Error Handling

**iOS:**
```objc
RCT_EXPORT_METHOD(riskyOperation:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  NSError *error = nil;
  id result = [self performOperation:&error];
  
  if (error) {
    reject(@"OPERATION_FAILED", error.localizedDescription, error);
  } else {
    resolve(result);
  }
}
```

**Android:**
```java
@ReactMethod
public void riskyOperation(Promise promise) {
    try {
        Object result = performOperation();
        promise.resolve(result);
    } catch (Exception e) {
        promise.reject("OPERATION_FAILED", e.getMessage(), e);
    }
}
```

## Advanced

For detailed platform-specific guides:
- [iOS Bridge](reference/ios-bridge.md) - Objective-C and Swift implementation
- [Android Bridge](reference/android-bridge.md) - Java and Kotlin implementation
- [Turbo Modules](reference/turbo-modules.md) - New architecture modules

## Troubleshooting

**Module not found:**
- Verify package.json configuration
- Run `pod install` (iOS) or rebuild (Android)
- Check module name matches in native code

**Methods not available:**
- Ensure RCT_EXPORT_METHOD is used
- Check method signature matches
- Rebuild native code

**Crashes on method call:**
- Check thread safety
- Verify data type conversions
- Add null checks
- Review error handling

**Events not received:**
- Verify supportedEvents (iOS)
- Check event emitter setup
- Ensure listeners are added before events fire

## Best Practices

1. **Minimize bridge calls**: Batch operations, use events for updates
2. **Type safety**: Use TypeScript interfaces
3. **Error handling**: Always handle errors gracefully
4. **Threading**: Move heavy operations off main thread
5. **Memory management**: Clean up resources, remove listeners
6. **Testing**: Test on both iOS and Android
7. **Documentation**: Document API clearly
8. **Versioning**: Use semantic versioning

Attribution

armanzeroeightarmanzeroeight
View sourceSee grades on GitHubMore from armanzeroeight →
SSkills Directory ProSkills Directory

Get any skill into Claude in one click.

Download any skill as a ZIP for Claude.ai, Claude Desktop, or .claude/skills. $9/mo.

See Pro

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills Directory ProSkills Directory

Get any skill into Claude in one click.

Download any skill as a ZIP for Claude.ai, Claude Desktop, or .claude/skills. $9/mo.

See Pro

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

285172 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10311 votes
View all in development →