Skip to main content

Capacitor integration

This guide describes SDK installation in your Capacitor application and the capture-then-upload workflow. See the overview for delivery, the SDK key and environments.

Prerequisites​

  • Capacitor 7, with its Android and/or iOS platforms and the build tools required by Capacitor.
  • Xcode and CocoaPods for iOS; Android Studio for Android.
  • The certificall-mobile-sdk-capacitor-<version>.tgz package provided by Certificall.
  • A physical device to validate the production workflow.

Capture and upload work in the native iOS or Android application. These methods are unavailable in a browser, including with ionic serve.

1. Install and synchronize​

Copy the delivered package to vendor/, then declare the dependency:

Coming from 2.0.0?

The package is now named @certificall/mobile-sdk-capacitor: rename the dependency key and your imports. The motion permission no longer exists: request ['camera', 'location']. The rest of the API is unchanged.

{
"dependencies": {
"@certificall/mobile-sdk-capacitor": "file:./vendor/certificall-mobile-sdk-capacitor-<version>.tgz"
}
}
npm install
npx cap sync

The package contains the native binaries. cap sync installs the plugin into your application's platforms.

2. Configure iOS permissions​

Add to Info.plist:

<key>NSCameraUsageDescription</key>
<string>Required to capture certified photos.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Required to certify the photo's location.</string>
<key>NSMotionUsageDescription</key>
<string>Required to collect motion during capture.</string>

You do not need photo library permission. Configure your application's signing in Xcode before running it on a device.

3. Configure Android​

Declare permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

The SDK includes its own file provider and the declarations needed to detect the camera. You do not need to add a FileProvider for the SDK.

Synchronize, then rebuild the native application:

npx cap sync android
npx cap open android

For iOS:

npx cap sync ios
npx cap open ios

4. Request permissions and initialize​

Request permissions before initialization, which starts position and motion collection. This example prepares the workflow after location access and, on Android, camera access have been granted.

import { Capacitor } from '@capacitor/core';
import { CertificallTrust } from '@certificall/mobile-sdk-capacitor';

export async function prepareCapture(): Promise<boolean> {
const permissions = await CertificallTrust.requestPermissions({
permissions: ['camera', 'location'],
});
if (permissions.location !== 'granted') return false;
if (
Capacitor.getPlatform() === 'android' &&
permissions.camera !== 'granted'
) {
return false;
}

await CertificallTrust.initialize({
apiKey: '<your SDK API key>',
baseUrl: 'https://dev.certificall.app/certificall/',
appVersion: '1.0.0',
});
return true;
}

On iOS, requestPermissions() requests location access; camera authorization is handled when the camera opens. The camera field returned by checkPermissions() is not a check of the iOS system authorization.

Call preparation when your screen opens. appVersion is the version of your application.

5. Capture, then upload​

import { CertificallTrust } from '@certificall/mobile-sdk-capacitor';

const photo = await CertificallTrust.takePhoto({
reportToken: 'JOB-2026-001',
metadata: { site: 'Paris', zone: 'A1' },
});

// Save this JSON to your storage before upload if the capture
// must survive the application being closed.
const serializedPhoto = JSON.stringify(photo);

const sent = await CertificallTrust.sendPhoto({ photo });
console.log('Case:', sent.caseId);
console.log('PDF certificate:', sent.pdfUrl);
console.log('Warnings:', sent.warnings);

The serializedPhoto variable is not persistent storage. Your application chooses how to save it, read it back and trigger upload. See Storage and retries.

sendPhoto signature

With Capacitor, pass { photo } to sendPhoto(). With React Native, pass the capture directly.

API surface​

MethodReturn valueUse
initialize({ apiKey, baseUrl, appVersion })Promise<void>Configuration; all three parameters are required.
checkPermissions()Promise<PermissionStatus>Permission states reported by the plugin.
requestPermissions({ permissions })Promise<PermissionStatus>Request permissions.
takePhoto({ reportToken?, metadata? }?)Promise<CapturedPhoto>Local capture with its signals.
sendPhoto({ photo })Promise<SentPhoto>Upload and certification.
isDebugBuild()Promise<{ debugBuild: boolean }>Application build type.
getNetworkStatus()Promise<{ connected, connectionType }>Current network status.
startNetworkMonitoring()Promise<void>Enable networkStatusChange events.
stopNetworkMonitoring()Promise<void>Stop network monitoring.
getCurrentPosition()Promise<LocationPosition>Current position.
watchPosition(callback)Promise<string>Position monitoring; returns an identifier.
getCurrentMotion()Promise<MotionData>Current motion.
watchMotion(callback)Promise<string>Motion monitoring; returns an identifier.
clearWatch({ id })Promise<void>Stop position or motion monitoring.
getDeviceSnapshot({ includeLocation?, includeMotion? })Promise<DeviceSnapshot>Device snapshot.

For capture and upload errors, read error.code and additional data in error.data: reasons, status and reason. See the error reference.

Monitor connectivity​

You can use network events to decide when to process your upload queue:

const listener = await CertificallTrust.addListener(
'networkStatusChange',
status => {
console.log(status.connected, status.connectionType);
// When connectivity returns, your application can process its queue.
},
);
await CertificallTrust.startNetworkMonitoring();

// When monitoring ends:
await CertificallTrust.stopNetworkMonitoring();
await listener.remove();

connectionType is wifi, cellular, none or unknown. A connected status does not guarantee that Certificall is reachable: also handle sendPhoto() errors.

Troubleshooting​

SymptomCheck
Plugin not detectedRun npm install and npx cap sync again, then rebuild the application.
Capture unavailable in a browserRun the application on iOS or Android.
Android permission deniedRequest permissions before initialize().
NOT_INITIALIZEDWait for initialize() to resolve before capture or upload.
DEVICE_NOT_TRUSTEDRead error.data.reasons and device checks.
INVALID_PHOTOPass { photo } with the complete object returned by takePhoto().
SERVER_REJECTEDCheck error.data.status, error.data.reason, the key and environment URL.
Development photo rejectedUse pre-production; for production, take a new photo with a distribution build.