-
Notifications
You must be signed in to change notification settings - Fork 32
Android SDK Behavior Changes and Migration (v3.16 )
We have recently release 3.16.0v for Mobile SDK. And with this release there are few behaviour changes. This guide explains two behavior updates introduced in the Android SDK and how to migrate apps:
- Support for 16 KB memory page size (Google-recommended platform change)
- App-owned runtime permission handling (SDK no longer prompts)
Both are intentional behavior changes. The 16 KB work is non-breaking for apps; the permission model is a breaking change that requires app updates.
Newer Android devices and toolchains can use a default memory page size of 16 KB on arm64. Google has announced a Play compatibility requirement: starting November 1, 2025, all new apps and updates targeting Android 15+ devices must support 16 KB page sizes on 64-bit devices. See guidance: Google: Support 16 KB page sizes.
- Updated native components and packaging to be compatible with 16 KB memory pages (e.g., proper ELF alignment, toolchain flags, and mapping behavior).
- Ensured the SDK runs correctly on devices using 16 KB pages without app-side changes.
- No app code changes required. Updating to this SDK version is sufficient.
- Validation tip: on a test device/emulator,
adb shell getconf PAGE_SIZEshould return16384when running with 16 KB pages (see Google doc linked above).
- SDK does not include dangerous permissions in its library manifest; applications must declare them in their own manifests.
- SDK does not prompt for system permissions; applications must request them at runtime.
- SDK performs preflight checks and reports missing permissions via
WebexError.ErrorCode.PERMISSION_REQUIRED(with the missing permission list inerror.data). - There is a change in how user consent for screen sharing is obtained.
- Flexibility: Apps can adopt the latest Android UX patterns for permission prompts and custom UI flows.
- Independence: Reduces app coupling to SDK releases when Google updates permission policies.
- Store compliance: Apps can control which permissions are declared per flavor, minimizing Play Console warnings for dangerous/sensitive permissions.
- Apps that previously relied on SDK-owned prompts will now receive
PERMISSION_REQUIREDerrors instead of dialog popups. - Migration is required to add manifest declarations, request permissions at runtime, and retry SDK calls after grants.
- Declare only the permissions your app actually needs per feature/flavor. Examples:
-
RECORD_AUDIO(audio) -
CAMERA(video) -
MODIFY_AUDIO_SETTINGS(required for audio routing - speaker, Bluetooth, earpiece) -
BLUETOOTH_CONNECTon API 31+ (Bluetooth route toggle; legacyBLUETOOTHon older) -
READ_PHONE_STATE(optional optimization) - No runtime string for screen share consent (MediaProjection); overlays require
SYSTEM_ALERT_WINDOWif your UX needs it
-
Request permissions before calling SDK APIs. Keep a small helper for checking and requesting.
val required = listOf(Manifest.permission.RECORD_AUDIO)
val missing = required.filter { ContextCompat.checkSelfPermission(ctx, it) != PackageManager.PERMISSION_GRANTED }
if (missing.isNotEmpty()) {
// requestPermissions(missing.toTypedArray(), REQ_CODE)
return
}If a call returns PERMISSION_REQUIRED, read error.data for the list of missing permissions, request them, and retry.

- Permissions:
RECORD_AUDIO - Flow:
- Check/request mic
- Call
webex.phone.dial(...)(oranswer(...)) - On
PERMISSION_REQUIRED, prompt and retry
val mic = Manifest.permission.RECORD_AUDIO
if (ContextCompat.checkSelfPermission(ctx, mic) != PackageManager.PERMISSION_GRANTED) {
// requestPermissions(arrayOf(mic), REQ_MIC)
return
}
webex.phone.dial(address, MediaOption.audioOnly()) { result -> /* handle */ }Dangerous permissions: RECORD_AUDIO is runtime (dangerous). Always prompt at runtime on Android 6+.
Manifest entries:
<uses-permission android:name="android.permission.RECORD_AUDIO" />- Permissions:
RECORD_AUDIO,CAMERA(plus optionalREAD_PHONE_STATEif enabled in your app) - Flow: request both, then dial/answer
val needed = arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
// request if missing ... then
webex.phone.dial(address, MediaOption.audioVideo(/* views */)) { result -> /* handle */ }Manifest entries:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />- No runtime permission string; must obtain the consent intent
- Flow:
- Launch
MediaProjectionManager#createScreenCaptureIntent() - On success, pass
data: Intenttocall.startSharing(consentData, ...)and proceed tostartSharing(...) - If overlays needed (e.g., annotations), check
Settings.canDrawOverlays(...)and guide user to Settings
- Launch
val mgr = ctx.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
val consentIntent = mgr.createScreenCaptureIntent()
launcher.launch(consentIntent)
// onActivityResult / ActivityResult callback:
call.startSharing(notification, notifId, data /* consent */, callback, shareConfig)Manifest entries:
<!-- No runtime permission string for MediaProjection consent -->
<!-- If your UX includes overlays (e.g., annotations), and you actually present them: -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />- Permissions:
-
MODIFY_AUDIO_SETTINGS(required for all audio routing - normal permission) -
BLUETOOTH_CONNECTon API 31+ for Bluetooth toggle (dangerous permission) - Legacy
BLUETOOTHon older Android versions
-
- Flow: declare
MODIFY_AUDIO_SETTINGSin manifest, request Bluetooth permission at runtime if needed, then callcall.switchAudioOutput(...)
Important: Without MODIFY_AUDIO_SETTINGS, toggling to speaker mode or any audio route will fail or produce no audio during calls.
// Switch to speaker (only needs MODIFY_AUDIO_SETTINGS in manifest)
call.switchAudioOutput(Call.AudioOutputMode.SPEAKER) { result ->
if (result.isSuccessful) {
// Audio routed to speaker
}
}
// Switch to Bluetooth (needs MODIFY_AUDIO_SETTINGS + runtime Bluetooth permission)
val bt = if (Build.VERSION.SDK_INT >= 31) Manifest.permission.BLUETOOTH_CONNECT else Manifest.permission.BLUETOOTH
if (ContextCompat.checkSelfPermission(ctx, bt) == PackageManager.PERMISSION_GRANTED) {
call.switchAudioOutput(Call.AudioOutputMode.BLUETOOTH_HEADSET) { /* handle */ }
} else {
// Request Bluetooth permission at runtime
}
// Switch to earpiece/phone
call.switchAudioOutput(Call.AudioOutputMode.PHONE) { /* handle */ }Manifest entries:
<!-- Required for ALL audio routing operations (normal permission - no runtime request needed) -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<!-- Only if your app uses Bluetooth audio routing -->
<!-- API 31+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Legacy (if supporting older targets) -->
<uses-permission android:name="android.permission.BLUETOOTH" />Note: MODIFY_AUDIO_SETTINGS is a normal permission (not dangerous), so it only needs manifest declaration. However, BLUETOOTH_CONNECT is a dangerous permission on API 31+ and requires runtime request.
- Some apps use
READ_PHONE_STATEto improve the call experience on certain devices or carriers. Keep it optional—request it only if your app truly benefits.
Example (only request if you need it):
val phoneState = Manifest.permission.READ_PHONE_STATE
val isGranted = ContextCompat.checkSelfPermission(ctx, phoneState) == PackageManager.PERMISSION_GRANTED
if (!isGranted) {
// requestPermissions(arrayOf(phoneState), REQ_READ_PHONE_STATE)
}SDK toggle:
Phone.enableAskingReadPhoneStatePermission(enable: Boolean)- Default is
true. When your target SDK ≥ 30, this permission is used to check network state so the SDK can auto‑tune performance during calls.
// If your app does not benefit from READ_PHONE_STATE, you can opt out
webex.phone.enableAskingReadPhoneStatePermission(false)Manifest entries:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />- If a preflight finds missing permissions, you’ll get
PERMISSION_REQUIREDwith a list inerror.data. - Request those permissions via your UI, then retry the exact API call.
- Avoid scenarios where the app displays a “missing permission” toast while the SDK proceeds—ensure your UI and SDK preflight are aligned.
- Split permissions by product flavor/module so you only declare what each build truly needs.
- This reduces Play Console warnings for unused dangerous permissions.
No. All prompts are app-owned. The SDK only validates and reports PERMISSION_REQUIRED.
No. Updating to this SDK is sufficient.
No for the same operation. If a preflight fails, the call is not executed. Ensure your app UI doesn’t show an unrelated permission toast while a separate flow proceeds.