Creating a Native Media Player in HarmonyOS Next
Creating a Native Media Player
When the enableNativeMediaPlayer
feature is enabled, the ArkWeb kernel will trigger the callback function registered by onCreateNativeMediaPlayer
whenever there is media to be played on a webpage.
Developers need to call onCreateNativeMediaPlayer
to register a callback function for creating a native media player.
The callback function should determine whether to create a native media player to take over the current webpage media resource based on the media information.
- If the application does not take over the current webpage media resource, the callback function should return
null
. - If the application takes over the current webpage media resource, the callback function should return an instance of a native media player.
The native media player must implement the NativeMediaPlayerBridge
interface to allow the ArkWeb kernel to control the playback operations of the native media player.
Example: Creating a Native Media Player
// xxx.ets
import { webview } from '@kit.ArkWeb';
// Implement the webview.NativeMediaPlayerBridge interface.
// The ArkWeb kernel calls methods of this class to control the NativeMediaPlayer.
class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge {
// ... Implement the methods of NativeMediaPlayerBridge ...
constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {}
updateRect(x: number, y: number, width: number, height: number) {}
play() {}
pause() {}
seek(targetTime: number) {}
release() {}
setVolume(volume: number) {}
setMuted(muted: boolean) {}
setPlaybackRate(playbackRate: number) {}
enterFullscreen() {}
exitFullscreen() {}
}
@Entry
@Component
struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController();
build() {
Column() {
Web({ src: 'https://www.example.com', controller: this.controller })
.enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
.onPageBegin((event) => {
this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
// Determine whether to take over the current media.
if (!shouldHandle(mediaInfo)) {
// The native media player does not take over this media.
// Return null. The ArkWeb kernel will use its own player to play the media.
return null;
}
// Take over the current media.
// Return a native media player instance to the ArkWeb kernel.
let nativePlayer: webview.NativeMediaPlayerBridge = new NativeMediaPlayerImpl(handler, mediaInfo);
return nativePlayer;
});
})
}
}
}
// Stub function to determine whether to handle the media.
function shouldHandle(mediaInfo: webview.MediaInfo): boolean {
return true;
}
Rendering the Native Media Player Component
After the application takes over the webpage media, developers need to render the native media player component and the video画面 onto the Surface provided by the ArkWeb kernel. The ArkWeb kernel then composites the Surface with the webpage and displays it on the screen.
This process is similar to the same-layer rendering process.
During the application startup phase, the UIContext
should be saved for use in the subsequent same-layer rendering process.
Example: Saving UIContext
// xxxAbility.ets
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
return;
}
// Save the UIContext for use in subsequent same-layer rendering.
AppStorage.setOrCreate<UIContext>("UIContext", windowStage.getMainWindowSync().getUIContext());
});
}
// ... Other methods to override ...
}
Using the Surface for Same-Layer Rendering
// xxx.ets
import { webview } from '@kit.ArkWeb';
import { BuilderNode, FrameNode, NodeController, NodeRenderType } from '@kit.ArkUI';
interface ComponentParams {}
class MyNodeController extends NodeController {
private rootNode: BuilderNode<[ComponentParams]> | undefined;
constructor(surfaceId: string, renderType: NodeRenderType) {
super();
// Retrieve the previously saved UIContext.
let uiContext = AppStorage.get<UIContext>("UIContext");
this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType });
}
makeNode(uiContext: UIContext): FrameNode | null {
if (this.rootNode) {
return this.rootNode.getFrameNode() as FrameNode;
}
return null;
}
build() {
// Construct the native media player component.
}
}
@Entry
@Component
struct WebComponent {
node_controller?: MyNodeController;
controller: webview.WebviewController = new webview.WebviewController();
@State show_native_media_player: boolean = false;
build() {
Column() {
Stack({ alignContent: Alignment.TopStart }) {
if (this.show_native_media_player) {
NodeContainer(this.node_controller)
.width(300)
.height(150)
.backgroundColor(Color.Transparent)
.border({ width: 2, color: Color.Orange })
}
Web({ src: 'https://www.example.com', controller: this.controller })
.enableNativeMediaPlayer({ enable: true, shouldOverlay: false })
.onPageBegin((event) => {
this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => {
// Take over the current media.
// Use the Surface provided by the same-layer rendering process to construct a native media player component.
this.node_controller = new MyNodeController(mediaInfo.surfaceInfo.id, NodeRenderType.RENDER_TYPE_TEXTURE);
this.node_controller.build();
// Display the native media player component.
this.show_native_media_player = true;
// Return a native media player instance to the ArkWeb kernel.
return null;
});
})
}
}
}
}
Top comments (0)