An extension consists of a TypedExtensionService and an ExtensionManifest. Start from the
Hello sample, then replace its identity and features with your own.
dependencies {
implementation(project(":extension:sdk-android"))
}Add this Service entry to the extension's AndroidManifest.xml, changing only the class name:
<service
android:name=".HelloExtensionService"
android:exported="true"
android:permission="com.m3u.permission.BIND_EXTENSION_HOST">
<intent-filter>
<action android:name="com.m3u.extension.action.BIND_EXTENSION" />
</intent-filter>
</service>External extensions use the host broker for network access. An extension that declares android.permission.INTERNET is listed as incompatible.
The declared class must extend TypedExtensionService:
class HelloExtensionService : TypedExtensionService() {
override val extensionManifest = ExtensionManifest(
id = ExtensionId("com.m3u.samples.hello"),
displayName = "Hello Extension",
extensionVersion = ExtensionSemanticVersion(1, 0, 0),
apiRange = ExtensionApiRange(
minimum = ExtensionApiVersions.Current,
maximum = ExtensionApiVersions.Current,
),
hooks = emptySet(),
capabilities = emptySet(),
metadata = mapOf("developer" to "M3UAndroid sample"),
)
}Replace these values:
| Value | What to enter |
|---|---|
id |
A lowercase, stable ID owned by your extension. |
displayName |
The name shown by M3UAndroid. |
extensionVersion |
This extension build's version. |
apiRange |
The M3UAndroid extension API range this build supports. |
metadata["developer"] |
The developer name shown with the extension. |
The handler and manifest declaration use the same HookSpec. Every item in
requiredCapabilities also needs an ExtensionCapabilityRequest with a concrete user-facing
reason. The next page adds a complete settings Hook declaration and handler.
Put fields that do not depend on the current request in settingsSchema:
settingsSchema = ExtensionSettingSchema(
version = 1,
fields = listOf(
ExtensionSettingField(
key = "greeting",
label = "Greeting",
type = ExtensionSettingType.TEXT,
defaultValue = JsonPrimitive("Hello from my extension"),
)
),
)M3UAndroid renders and stores these values. Use the settings Hook instead when fields depend on its request, such as request.surface.
Keep the extension identity stable when publishing an update. The exact identity fields are listed in Prepare a release or update.
Next: register the typed Hook.