Conch API Reference
1. Core APIs
1.1 runAppWrapper - Application startup wrapper
1.1.1 Overview
runAppWrapper is the core startup method of the Conch SDK. It wraps the Flutter app startup flow and automatically handles patch loading, app initialization, and global exception capture.
1.1.2 Workflow
Exception handler installation: Installs global exception handlers inside
runZonedGuardedto capture three types of exceptions:- Flutter framework synchronous exceptions (
FlutterError.onError) - Engine asynchronous exceptions (
PlatformDispatcher.instance.onError) - Zone fallback exceptions (
runZonedGuardedonError)
- Flutter framework synchronous exceptions (
Initialization phase: Automatically completes SDK initialization and sets configuration parameters and callbacks
Patch handling: Loads patches according to configuration
App startup: Calls
appBuilder()to start the app
1.1.3 Function signature
static void runAppWrapper(
ConchParams params, {
required FutureOr<void> Function() appBuilder,
PatchInstallCallback? patchInstallCallback,
PatchLoadCallback? patchLoadCallback,
AppErrorHandlingConfig errorConfig = const AppErrorHandlingConfig(),
})
1.1.4 Parameters
ConchParams details
| Parameter | Type | Required | Description |
|---|---|---|---|
appId | String | Yes | Unique app identifier from the Shiply platform |
appKey | String | Yes | Obtained from the Shiply release platform; must match platform configuration for security validation |
moduleName | String | Yes | Module name; must match the Shiply platform |
appVersion | String | Yes | App version used for patch delivery version matching |
env | String | No | Environment identifier; defaults to "online" (production) |
deviceId | String | No | Device identifier for staged rollout and allowlists |
Note: appId, appKey, and moduleName must exactly match Shiply platform configuration; otherwise patches cannot be fetched.
runAppWrapper parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
params | ConchParams | Yes | - | Conch runtime configuration including appId, appKey, moduleName, etc. |
appBuilder | FutureOr<void> Function() | Yes | - | App startup function; caller must call runApp inside. Supports sync or async execution. Called after patch loading completes. Typical usage: appBuilder: () => runApp(MyApp()) |
patchInstallCallback | PatchInstallCallback? | No | null | Callback when patch installation completes; returns PatchInstallResult with result code, version, etc. |
patchLoadCallback | PatchLoadCallback? | No | null | Callback when patch loading completes; returns PatchLoadResult with result code, module name, version, etc. |
errorConfig | AppErrorHandlingConfig | No | const AppErrorHandlingConfig() | App-level exception capture and handling configuration for customizing the three exception types |
errorConfig details
errorConfig is an AppErrorHandlingConfig object used to configure app-level exception handling:
class AppErrorHandlingConfig {
/// Flutter framework synchronous exception handler
/// Return value: true if handled (stops propagation); false if unhandled (delegates to the system default handler)
final bool Function(FlutterErrorDetails details)? onFlutterError;
/// Engine asynchronous exception handler
/// Return value: true if handled (stops propagation); false if unhandled (delegates to the system default handler)
final bool Function(Object error, StackTrace stackTrace)? onPlatformError;
/// Zone fallback exception handler
/// Return value: true if handled (stops propagation); false if unhandled (forwards to the parent Zone)
final bool Function(Object error, StackTrace stackTrace)? onZonedError;
}
Exception handling flow:
- Conch logs the exception first (for patch safe-mode management)
- Calls the callback configured by the app
- Decides whether to propagate the exception based on the callback return value
Return value:
- Type:
void - Description: No return value. This method calls
runApp()internally, so you do not need to callrunApp()again externally
1.1.5 Examples
Basic usage (no exception handling)
void main() {
ConchLoaderAPI.runAppWrapper(
params,
appBuilder: () => runApp(const MyApp()),
patchInstallCallback: (result) {
print('Patch install result: ${result.resultCode}');
},
patchLoadCallback: (result) {
print('Patch load result: ${result.resultCode}');
},
);
}
Full usage (with exception handling)
void main() {
ConchLoaderAPI.runAppWrapper(
params,
appBuilder: () => runApp(const MyApp()),
patchInstallCallback: (result) {
print('Patch install result: ${result.resultCode}');
},
patchLoadCallback: (result) {
print('Patch load result: ${result.resultCode}');
},
errorConfig: AppErrorHandlingConfig(
// Handle Flutter framework synchronous exceptions
onFlutterError: (FlutterErrorDetails details) {
// Record the exception in the monitoring system
Crashlytics.recordFlutterError(details);
// Show a user-friendly error message
if (isCriticalError(details.exception)) {
showErrorDialog(details.exception.toString());
return true; // Prevent the default red error screen
}
return false; // Let the system continue handling
},
// Handle engine asynchronous exceptions
onPlatformError: (Object error, StackTrace stack) {
// Report the exception
Crashlytics.recordError(error, stack);
// Handle specific exceptions
if (error is NetworkException) {
showNetworkErrorToast();
return true;
}
return false;
},
// Handle Zone fallback exceptions
onZonedError: (Object error, StackTrace stackTrace) {
debugPrint('Unhandled app exception: $error');
// Emergency recovery strategy
if (shouldRestartApp(error)) {
restartApp();
return true;
}
return false;
},
),
);
}
1.1.6 Notes
- You must call
runApp()insideappBuilder:runAppWrapperno longer callsrunApp()automatically; call it insideappBuilder, e.g.appBuilder: () => runApp(MyApp()) - Exception handler return values: Return values in
errorConfigcallbacks are important:true: Business handled the exception; Conch stops propagationfalse: Business did not handle it; Conch delegates to the original handler
- Debug mode limitation: Conch patch functionality only works in
Releasemode, but exception handling also works in Debug mode - Defensive programming: Wrap logic inside
errorConfigcallbacks with try/catch to avoid the handler itself throwing
1.2 requestPatch - Patch request API
1.2.1 Overview
Fetches patches from the server and installs them locally only; does not load them into the runtime.
1.2.2 Function signature
static Future<PatchInstallResult> requestPatch()
1.2.3 Core characteristics
- Network-only operation: Downloads and decrypts patches locally without loading into the runtime
- Async execution: Non-blocking; suitable for background execution
- Independent invocation: Can be called at any time; not tied to app startup
- Pre-download: Download patches in advance for loading after cold start
Return value:
Type: Future<PatchInstallResult>
PatchInstallResult fields:
resultCode: Install status code (SUCCESS,FETCH_NO_PATCH,NOT_INIT,INSTALL_FAIL, etc.)moduleName: Module nameversion: Patch versiontaskId: Task ID
1.2.4 Example
// Pre-download patch in the background (non-blocking)
ConchLoaderAPI.requestPatch().then((result) {
if (result.resultCode == PatchInstallResultCode.SUCCESS) {
print('Patch downloaded and installed locally: ${result.version}');
} else {
print('Patch install failed or no patch available: ${result.resultCode}');
}
});
1.2.5 Notes
- This method only downloads and installs patches; it does not load them into the runtime
- Downloaded patches are loaded automatically on the next app startup
1.3 queryPatchLoadResult - Patch load status query
1.3.1 Overview
Synchronously queries the current patch load result without triggering any load flow.
1.3.2 Function signature
static PatchLoadResult? queryPatchLoadResult()
1.3.3 Core characteristics
- Query only: Does not trigger network requests or patch loading
Return value:
Type: PatchLoadResult?
Return value description:
- Non-null: Contains current patch load status
resultCode: Load status code (SUCCESS,NO_PATCH,PATCH_LOAD_FAIL, etc.)moduleName: Module nameversion: Patch versiontaskId: Task ID
- null: Returned when:
- Patch loading has not started or the load flow is not complete
1.3.4 Examples
// Basic usage
final result = ConchLoaderAPI.queryPatchLoadResult();
if (result != null) {
if (result.resultCode == PatchLoadResultCode.SUCCESS) {
print('Currently loaded patch version: ${result.version}');
} else {
print('Patch not loaded or load failed: ${result.resultCode}');
}
} else {
print('SDK not initialized, patch loading not started, or load flow incomplete');
}
// Use in business logic
Widget build(BuildContext context) {
final patchResult = ConchLoaderAPI.queryPatchLoadResult();
final version = patchResult?.version ?? 'Unknown';
return Text('Current patch version: $version');
}
1.3.5 Notes
- Synchronous method; does not block the thread
- Status query only; does not change runtime state
- Recommended to call after app startup completes
2. Safe mode configuration APIs
The Conch SDK provides a safe-mode mechanism to automatically detect and block faulty patches and protect app stability. Use the following APIs to configure safe-mode behavior.
Available in SDK 1.7.2 and later.
2.1 Core concepts
How safe mode works:
- Exception detection window: Time range from app startup; only exceptions in this window count
- Exception count: Consecutive exceptions for a patch within the detection window (a success resets the count)
- Success count: Consecutive successful runs for a patch (an exception resets the count)
- Marked unsafe: When consecutive exceptions reach the threshold, the patch is marked unsafe and blocked from loading
- Marked safe: When consecutive successes reach the threshold, the patch is marked safe and safe mode will not block it
2.2 API list
setMarkPatchUnsafeThreshold - Set patch exception threshold
Description:
- Sets the consecutive exception threshold that triggers safe mode
- When consecutive exceptions reach the threshold, the patch is marked unsafe and blocked from loading
Function signature:
static bool setMarkPatchUnsafeThreshold(int threshold)
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
threshold | int | Yes | Consecutive exception threshold; must be >= 1 |
Return value:
true: Setting succeededfalse: Setting failed (threshold < 1)
Example:
// Set consecutive exception threshold to 5
bool success = ConchLoaderAPI.setMarkPatchUnsafeThreshold(5);
if (success) {
print('Exception threshold set successfully');
}
setMarkPatchSafeThreshold - Set patch consecutive success threshold
Description:
- Sets the consecutive success threshold for a patch
- When consecutive successes reach the threshold, the patch is marked safe; safe mode allows loading by default
Function signature:
static bool setMarkPatchSafeThreshold(int threshold)
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
threshold | int | Yes | Consecutive success threshold; must be >= 1 |
Return value:
true: Setting succeededfalse: Setting failed (threshold < 1)
Example:
// Set consecutive success threshold to 10
bool success = ConchLoaderAPI.setMarkPatchSafeThreshold(10);
if (success) {
print('Safe threshold set successfully');
}
setSafeModeWindowSeconds - Set safe mode detection window
Description:
- Sets the safe mode app detection window in seconds
- Configures the exception detection time window from app startup
- Only exceptions within this window count toward safe-mode exception counting
Function signature:
static bool setSafeModeWindowSeconds(int windowSeconds)
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
windowSeconds | int | Yes | Time window in seconds; range [1, 60] |
Return value:
true: Setting succeededfalse: Setting failed (windowSeconds not in [1, 60])
Example:
// Set detection window to 5 seconds
bool success = ConchLoaderAPI.setSafeModeWindowSeconds(5);
if (success) {
print('Detection window set successfully');
}
getSafeModeWindowSeconds - Get safe mode detection window
Description:
- Returns the current safe mode app detection window in seconds
Function signature:
static int getSafeModeWindowSeconds()
Return value:
- Safe mode app detection window in seconds
Example:
int windowSeconds = ConchLoaderAPI.getSafeModeWindowSeconds();
print('Current detection window: $windowSeconds seconds');
getMarkPatchSafeThreshold - Get patch consecutive success threshold
Description:
- Returns the current patch consecutive success threshold
Function signature:
static int getMarkPatchSafeThreshold()
Return value:
- Patch consecutive success threshold
Example:
int threshold = ConchLoaderAPI.getMarkPatchSafeThreshold();
print('Current safe threshold: $threshold');
getMarkPatchUnsafeThreshold - Get patch exception threshold
Description:
- Returns the current patch exception threshold
Function signature:
static int getMarkPatchUnsafeThreshold()
Return value:
- Patch consecutive exception threshold
Example:
int threshold = ConchLoaderAPI.getMarkPatchUnsafeThreshold();
print('Current consecutive exception threshold: $threshold');
2.3 Full configuration example
void main() {
// Configure safe mode parameters (recommended before runAppWrapper)
ConchLoaderAPI.setMarkPatchUnsafeThreshold(5); // Mark unsafe after 5 consecutive exceptions
ConchLoaderAPI.setMarkPatchSafeThreshold(10); // Mark safe after 10 consecutive successes
ConchLoaderAPI.setSafeModeWindowSeconds(5); // Detection window: 5 seconds
// Start the app
ConchLoaderAPI.runAppWrapper(
params,
appBuilder: () => runApp(const MyApp()),
errorConfig: AppErrorHandlingConfig(
onFlutterError: (details) {
// Business exception handling logic
return false;
},
),
);
}
2.4 Notes
- Call timing: Configure safe mode before
runAppWrapper - Defaults: If not configured, defaults are:
- Consecutive exception threshold: 3
- Consecutive success threshold: 5
- Detection window: 3 seconds
- Release mode only: Safe mode only applies in Release mode; Debug mode does not block patches
- Persistent storage: Safe-mode counters persist across app restarts
- Patch updates: Counters reset automatically when the patch version changes (MD5 change)