LEARN · DEBUGGING GUIDE

Capacitor Native Plugin Not Working: What to Check When the Bridge Breaks

When a Capacitor plugin stops working, the issue is almost always in the bridge—not the plugin code. This guide covers the exact commands, logs, and files to inspect.

IntermediateMobile8 min read

What this usually means

The bridge between JavaScript and native code is misconfigured. This often happens because the plugin's native pod/class is not registered, the plugin is not listed in Capacitor's configuration, or the native project was not properly synced after adding the plugin. On iOS, missing pod install or incorrect Podfile source can cause the native library to be unavailable. On Android, missing plugin registration in the MainActivity or incorrect Gradle dependencies are common culprits. Another frequent cause is a mismatch between the Capacitor core version and the plugin's expected version, leading to broken API contracts.

( 01 )Fast diagnosis

The first ten minutes — establish facts before touching code.

  • 1Run 'npx cap sync' from the project root and check for errors (this regenerates native project files).
  • 2Check the native console (Xcode or Android Studio logcat) for plugin-specific error messages—filter by 'CAP' or plugin name.
  • 3Verify the plugin is listed in 'capacitor.config.json' under 'plugins' (if it requires configuration).
  • 4On iOS, open the .xcworkspace file and check that the plugin pod is in the Pods project and linked to your target.
  • 5On Android, inspect 'MainActivity.java' or 'MainActivity.kt' for the plugin's @CapacitorPlugin annotation and import.
  • 6In the browser's JS console, log the plugin object: 'console.log(Plugins.YourPlugin)' — if undefined, the JS bridge is broken.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • searchcapacitor.config.json — plugin configuration block
  • searchios/App/Podfile — verify pod source and plugin pod entry
  • searchios/App/AppDelegate.swift — check plugin registration (if custom)
  • searchandroid/app/src/main/java/.../MainActivity.java — look for @CapacitorPlugin annotation
  • searchandroid/app/build.gradle — plugin dependency line (implementation)
  • searchnode_modules/@capacitor/your-plugin/ — check the plugin's package.json and native files
  • searchXcode console or Android logcat with filter 'Capacitor' or plugin name
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warningNative project not synced after plugin install (forgot 'npx cap sync')
  • warningiOS pod not installed due to missing 'pod install' or incorrect Podfile
  • warningAndroid plugin not registered in MainActivity (missing @CapacitorPlugin annotation)
  • warningPlugin version incompatible with Capacitor core version (check peerDependencies)
  • warningCapacitor.config.json plugin configuration missing required fields (e.g., apiKey)
  • warningPlugin requires a build phase script that wasn't added (e.g., GoogleMaps in Info.plist)
  • warningCapacitor web plugin running instead of native (check import paths)
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildRun 'npx cap sync' then 'npx cap copy' to ensure native files are regenerated.
  • buildOn iOS, delete Podfile.lock, run 'pod install --repo-update', then rebuild.
  • buildOn Android, add the plugin's class to the 'plugins' array in MainActivity's @CapacitorPlugin annotation.
  • buildCheck plugin's README for required permissions and add them to Info.plist (iOS) or AndroidManifest.xml (Android).
  • buildEnsure the plugin is imported correctly: for web fallback, use '@capacitor/plugin' not 'capacitor-plugin'.
  • buildClear node_modules and reinstall: 'rm -rf node_modules && npm install && npx cap sync'.
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedRun 'npx cap doctor' to check for common configuration issues.
  • verifiedTest a simple plugin method (e.g., Plugins.YourPlugin.echo({value: 'test'})) and log the result.
  • verifiedOn iOS, set a breakpoint in the plugin's native method and verify it's called.
  • verifiedOn Android, add a log statement in the plugin's native method and check logcat.
  • verifiedBuild and run a fresh release build (not debug) to rule out dev-only issues.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningEditing native files directly without running 'npx cap copy' afterward (changes get overwritten).
  • warningAssuming the plugin works because it's in package.json—Capacitor needs explicit registration.
  • warningMixing up Capacitor 2 and Capacitor 3+ plugin APIs (e.g., call vs. notifyListeners).
  • warningForgetting to run 'npx cap sync' after any plugin add or remove.
  • warningIgnoring the plugin's native dependencies (e.g., Google Play Services version mismatches).
  • warningTesting only on web simulator and not on a physical device or emulator.
( 07 )War story

Camera Plugin Fails Silently After Adding via npm

Mobile Developer, 3 years experienceIonic React, Capacitor 4, iOS 16, Camera plugin 4.1.0

Timeline

  1. 09:15Ran 'npm install @capacitor/camera' and added import to component.
  2. 09:20Called await Camera.getPhoto() in a button handler.
  3. 09:22Tested on iOS simulator — nothing happens, no error in console.
  4. 09:30Checked Xcode console: 'Plugin Camera not implemented on this platform'.
  5. 09:35Ran 'npx cap ls' — camera plugin not listed.
  6. 09:40Ran 'npx cap sync' — saw it added the plugin to native projects.
  7. 09:45Rebuilt app on simulator — Camera.getPhoto() now works.

I was adding the Capacitor Camera plugin to an existing Ionic React app. I had done this before with other plugins, so I just ran npm install and started coding. The import looked right: import { Camera, CameraResultType } from '@capacitor/camera'. I wired up a button to call await Camera.getPhoto(). Nothing happened when I clicked it. No error in the browser console, no popup, nothing.

I opened Xcode and ran the app, watching the console. I saw a log line: "[capacitor] Plugin Camera not implemented on this platform". That's when I realized the native side wasn't registered. I ran npx cap ls and indeed the camera plugin was not listed. I had forgotten to run npx cap sync after installing the npm package. I had assumed npm install was enough, but Capacitor needs to sync the native projects.

After running npx cap sync, I saw it add the camera pod and Java class. I rebuilt the app, clicked the button again, and the camera opened. The whole thing took 30 minutes of confusion for a two-second fix. I now make it a habit to always run npx cap sync after any plugin install.

Root cause

Forgot to run 'npx cap sync' after installing the plugin, so native code was never added to the Xcode project.

The fix

Ran 'npx cap sync' and rebuilt the app. The plugin started working immediately.

The lesson

Always run 'npx cap sync' after adding any Capacitor plugin. It's not optional.

( 08 )How Capacitor's Plugin Bridge Works

Capacitor plugins consist of a JavaScript wrapper and a native implementation. When you import a plugin in your JS code, the Capacitor runtime looks up the plugin name in a registry. On the native side, the plugin must be registered via an annotation (Android) or added to the plugin list (iOS). The bridge uses a call/notify pattern: JS sends a message with a plugin name, method, and arguments; the native side dispatches to the registered plugin class.

If the native class is not registered, the bridge returns an error: 'not implemented'. This is the most common failure mode. The registration happens automatically when you use 'npx cap add' or 'npx cap sync', but manual edits can break it. On iOS, the plugin's Podfile entry must be present and the pod must be installed. On Android, the plugin's Java class must be listed in the @CapacitorPlugin annotation in MainActivity.

( 09 )iOS-Specific Debugging: Podfile and Xcode

On iOS, the plugin is installed as a CocoaPod. If the plugin isn't working, first check your Podfile (ios/App/Podfile). It should contain a line like 'pod "CapacitorCamera"' (depending on the plugin). If it's missing, run 'npx cap sync' to regenerate it. Next, open the .xcworkspace (not .xcodeproj) and verify the Pods project contains the plugin's pod. If not, run 'pod install' from the ios/App directory.

Common pitfalls: using .xcodeproj instead of .xcworkspace, missing $(inherited) flags in build settings, or having multiple targets that don't include the plugin. Also check that the plugin's .swift or .m files are compiled in Build Phases → Compile Sources. If you see 'unrecognized selector sent to instance', the class is loaded but the method signature is wrong—usually a version mismatch.

( 10 )Android-Specific Debugging: Gradle and MainActivity

On Android, the plugin is a Java/Kotlin class annotated with @CapacitorPlugin(name="Camera"). This annotation must be present in your MainActivity's @CapacitorPlugin annotation as well (Capacitor 3+). If you have multiple plugins, they are listed in an array: @CapacitorPlugin(plugins = {Camera.class, ...}). Missing a plugin here means it won't be registered.

Also check the app-level build.gradle for the plugin dependency: 'implementation "com.capacitor:camera:4.1.0"'. If it's missing, add it. After changes, run 'Sync Project with Gradle Files' in Android Studio. A common issue is plugin version mismatches with Capacitor core — look at the plugin's package.json for peerDependencies. Using logcat with filter 'Capacitor/Plugin' can show registration errors.

( 11 )The 'npx cap sync' Command: What It Actually Does

Running 'npx cap sync' executes three steps: (1) 'npx cap copy' copies web assets into the native projects, (2) it regenerates the native plugin registrations based on node_modules, and (3) it runs 'pod install' on iOS. This is why forgetting this step breaks plugins. The command reads the package.json and capacitor.config.json to determine which plugins to include.

You can verify the sync worked by checking 'npx cap ls' — it lists all detected plugins. If your plugin isn't listed, sync didn't pick it up. Possible reasons: the plugin is not in node_modules, the plugin's package.json is missing a 'capacitor' entry, or the plugin version is incompatible. Running 'npx cap doctor' can also flag issues like missing native projects or misconfigured plugins.

( 12 )Web Fallback vs. Native Implementation

Some Capacitor plugins provide a web fallback that mimics native behavior in the browser. If you test only in a web preview, you might never notice the native plugin is broken. When you move to a device, the native implementation is used, and if it's missing, the bridge returns an error. Always test on a physical device or emulator early.

To force native only, you can check the platform: import { Capacitor } from '@capacitor/core' and use Capacitor.isNativePlatform(). If the plugin doesn't work on native, the issue is in the bridge. Also beware of multiple plugin registrations: if you import both the web and native versions, they might conflict. Use the standard import from '@capacitor/plugin' which handles the fallback automatically.

Frequently asked questions

Why does my Capacitor plugin work on Android but not on iOS?

This usually means the iOS native project wasn't properly synced. Run 'npx cap sync' to regenerate the iOS project files and Podfile. Then open the .xcworkspace and check that the plugin pod is installed. Also verify that the plugin's iOS implementation exists and is properly linked in Build Phases.

I ran 'npx cap sync' but the plugin still doesn't work. What next?

Check 'npx cap ls' — if the plugin is listed, the native registration is probably fine. Next, look at the console logs on the device. On iOS, run the app from Xcode and filter for 'CAP' or the plugin name. On Android, use logcat with 'Capacitor/Plugin' tag. Common issues: missing permissions, wrong method signature, or the plugin requires additional setup (like API keys in capacitor.config.json).

How do I manually register a Capacitor plugin on Android?

In your MainActivity.java, add the plugin class to the @CapacitorPlugin annotation. For example: @CapacitorPlugin(plugins = {Camera.class, Geolocation.class}). Also ensure the plugin dependency is in your app/build.gradle. If the plugin doesn't have an annotation, you might need to add it manually in the 'init' method of MainActivity using 'registerPlugin(MyPlugin.class)'.

What does 'Plugin not implemented' mean exactly?

It means the Capacitor runtime tried to call a method on the native side but the plugin class was not registered. This happens when the native project doesn't have the plugin's code linked. Run 'npx cap sync' and rebuild. If that doesn't help, check that the plugin's native code is actually present in the native project (e.g., Pods folder for iOS, Java folder for Android).

Can I use a Capacitor plugin without running 'npx cap sync'?

No. 'npx cap sync' is required to copy the plugin's native code into your iOS and Android projects. Without it, the plugin only exists in JavaScript and will fail at runtime on device. Always run 'npx cap sync' after installing any new plugin, and also after updating a plugin.