日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)鴻蒙OS教程:鴻蒙OS媒體會(huì)話開(kāi)發(fā)指導(dǎo)

場(chǎng)景介紹

AVSession 框架有四個(gè)主要的類,控制著整個(gè)框架的核心,下圖簡(jiǎn)單的說(shuō)明四個(gè)核心媒體框架控制類的關(guān)系。

  • AVBrowser

媒體瀏覽器,通常在客戶端創(chuàng)建,成功連接媒體服務(wù)后,通過(guò)媒體控制器 AVBrowse r向服務(wù)端發(fā)送播放控制指令。

其主要流程為,調(diào)用 connect 方法向 AVBrowserService 發(fā)起連接請(qǐng)求,連接成功后在回調(diào)方法 AVConnectionCallback.onConnected 中發(fā)起訂閱數(shù)據(jù)請(qǐng)求,并在回調(diào)方法 AVSubscriptionCallback.onAVElementListLoaded 中保存請(qǐng)求的媒體播放數(shù)據(jù)。

  • AVController

媒體控制器,在客戶端 AVBrowser 連接服務(wù)成功后的回調(diào)方法 AVConnectionCallback.onConnected 中創(chuàng)建,用于向 Service 發(fā)送播放控制指令,并通過(guò)實(shí)現(xiàn) AVControllerCallback 回調(diào)來(lái)響應(yīng)服務(wù)端媒體狀態(tài)變化,例如曲目信息變更、播放狀態(tài)變更等,從而完成UI刷新。

  • AVBrowser

Service

媒體瀏覽器服務(wù),通常在服務(wù)端,通過(guò)媒體會(huì)話 AVSession 與媒體瀏覽器建立連接,并通過(guò)實(shí)現(xiàn) Player 進(jìn)行媒體播放。其中有兩個(gè)重要的方法:

  1. onGetRoot,處理從媒體瀏覽器 AVBrowser 發(fā)來(lái)的連接請(qǐng)求,通過(guò)返回一個(gè)有效的 AVBrowserRoot 對(duì)象表示連接成功;
  2. onLoadAVElementList,處理從媒體瀏覽器 AVBrowser 發(fā)來(lái)的數(shù)據(jù)訂閱請(qǐng)求,通過(guò) AVBrowserResult.sendAVElementList(List) 方法返回媒體播放數(shù)據(jù)。
  • AVSession

媒體會(huì)話,通常在 AVBrowserService 的 onStart 中創(chuàng)建,通過(guò) setAVToken 方法設(shè)置到 AVBrowserService 中,并通過(guò)實(shí)現(xiàn) AVSessionCallback 回調(diào)來(lái)接收和處理媒體控制器 AVController 發(fā)送的播放控制指令,如播放、暫停、跳轉(zhuǎn)至上一曲、跳轉(zhuǎn)至下一曲等。

除了上述四個(gè)類,AVSession 框架還有 AVElement。

  • AVElement

媒體元素,用于將播放列表從 AVBrowserService 傳遞給 AVBrowser。

接口說(shuō)明

接口名 描述
AVBrowser(Context context, ElementName name, AVConnectionCallback callback, PacMap options) 構(gòu)造 AVBrowser 實(shí)例,用于瀏覽 AVBrowserService 提供的媒體數(shù)據(jù)。
void connect() 連接 AVBrowserService。
void disconnect() 與 AVBrowserService 斷開(kāi)連接。
boolean isConnected() 判斷當(dāng)前是否已經(jīng)與 AVBrowserService 連接。
ElementName getElementName() 獲取 AVBrowserService 的ohos.bundle.ElementName實(shí)例。
String getRootMediaId() 獲取默認(rèn)媒體 id。
PacMap getOptions() 獲取 AVBrowserService 提供的附加數(shù)據(jù)。
AVToken getAVToken() 獲取媒體會(huì)話的令牌。
void getAVElement(String mediaId, AVElementCallback callback) 輸入媒體的 id,查詢對(duì)應(yīng)的 ohos.media.common.sessioncore.AVElement 信息,查詢結(jié)果會(huì)通過(guò) callback 返回。
void subscribeByParentMediaId(String parentMediaId, AVSubscriptionCallback callback) 查詢指定媒體 id 包含的所有媒體元素信息,并訂閱它的媒體信息更新通知。
void subscribeByParentMediaId(String parentMediaId, PacMap options, AVSubscriptionCallback callback) 基于特定于服務(wù)的參數(shù)來(lái)查詢指定媒體 id 中的媒體元素的信息,并訂閱它的媒體信息更新通知。
void unsubscribeByParentMediaId(String parentMediaId) 取消訂閱對(duì)應(yīng)媒體 id 的信息更新通知。
void unsubscribeByParentMediaId(String parentMediaId, AVSubscriptionCallback callback) 取消訂閱與指定 callback 相關(guān)的媒體 id 的信息更新通知。
接口名 描述
abstract AVBrowserRoot onGetRoot(String callerPackageName, int clientUid, PacMap options) 回調(diào)方法,用于返回應(yīng)用程序的媒體內(nèi)容的根信息,在 AVBrowser.connect()后進(jìn)行回調(diào)。
abstract void onLoadAVElementList(String parentMediaId, AVBrowserResult result) 回調(diào)方法,用于返回應(yīng)用程序的媒體內(nèi)容的結(jié)果信息 AVBrowserResult,其中包含了子節(jié)點(diǎn)的 AVElement 列表,在 AVBrowser 的方法 subscribeByParentMediaId 或 notifyAVElementListUpdated 執(zhí)行后進(jìn)行回調(diào)。
abstract void onLoadAVElement(String mediaId, AVBrowserResult result) 回調(diào)方法,用于獲取特定的媒體項(xiàng)目 AVElement 結(jié)果信息,在 AVBrowser.getAVElement 方法執(zhí)行后進(jìn)行回調(diào)。
AVToken getAVToken() 獲取 AVBrowser 與 AVBrowserService 之間的會(huì)話令牌。
void setAVToken(AVToken token) 設(shè)置 AVBrowser 與 AVBrowserService 之間的會(huì)話令牌。
final PacMap getBrowserOptions() 獲取 AVBrowser 在連接 AVBrowserService 時(shí)設(shè)置的服務(wù)參數(shù)選項(xiàng)。
final AVRemoteUserInfo getCallerUserInfo() 獲取當(dāng)前發(fā)送請(qǐng)求的調(diào)用者信息。
void notifyAVElementListUpdated(String parentMediaId) 通知所有已連接的 AVBrowser 當(dāng)前父節(jié)點(diǎn)的子節(jié)點(diǎn)已經(jīng)發(fā)生改變。
void notifyAVElementListUpdated(String parentId, PacMap options) 通知所有已連接的 AVBrowser 當(dāng)前父節(jié)點(diǎn)的子節(jié)點(diǎn)已經(jīng)發(fā)生改變,可設(shè)置服務(wù)參數(shù)。
接口名 描述
AVController(Context context, AVToken avToken) 構(gòu)造 AVController 實(shí)例,用于應(yīng)用程序與 AVSession 進(jìn)行交互以控制媒體播放。
static boolean setControllerForAbility(Ability ability, AVController controller) 將媒體控制器注冊(cè)到 ability 以接收按鍵事件。
boolean setAVControllerCallback(AVControllerCallback callback) 注冊(cè)一個(gè)回調(diào)以接收來(lái)自 AVSession 的變更,例如元數(shù)據(jù)和播放狀態(tài)變更。
boolean releaseAVControllerCallback(AVControllerCallback callback) 釋放與 AVSession 之間的回調(diào)實(shí)例。
List getAVQueueElement() 獲取播放隊(duì)列。
CharSequence getAVQueueTitle() 獲取播放隊(duì)列的標(biāo)題。
AVPlaybackState getAVPlaybackState() 獲取播放狀態(tài)。
boolean dispatchAVKeyEvent(KeyEvent keyEvent) 應(yīng)用分發(fā)媒體按鍵事件給會(huì)話以控制播放。
void sendCustomCommand(String command, PacMap pacMap, GeneralReceiver receiverCb) 應(yīng)用向 AVSession 發(fā)送自定義命令,參考o(jì)hos.media.common.sessioncore.AVSessionCallback.onCommand。
IntentAgent getAVSessionAbility() 獲取啟動(dòng)用戶界面的IntentAgent。
AVToken getAVToken() 獲取應(yīng)用連接到會(huì)話的令牌。此令牌用于創(chuàng)建媒體播放控制器。
void adjustAVPlaybackVolume(int direction, int flags) 調(diào)節(jié)播放音量。
void setAVPlaybackVolume(int value, int flags) 設(shè)置播放音量,要求支持絕對(duì)音量控制。
PacMap getOptions() 獲取與此控制器連接的AVSession的附加數(shù)據(jù)。
long getFlags() 獲取 AVSession 的附加標(biāo)識(shí),標(biāo)記在 AVSession 中的定義。
AVMetadata getAVMetadata() 獲取媒體資源的元數(shù)據(jù)ohos.media.common.AVMetadata。
AVPlaybackInfo getAVPlaybackInfo() 獲取播放信息。
String getSessionOwnerPackageName() 獲得 AVSession 實(shí)例的應(yīng)用程序的包名稱。
PacMap getAVSessionInfo() 獲取會(huì)話的附加數(shù)據(jù)。
PlayControls getPlayControls() 獲取一個(gè) PlayControls 實(shí)例,將用于控制播放,比如控制媒體播放、停止、下一首等。
接口名 描述
AVSession(Context context, String tag) 構(gòu)造 AVSession 實(shí)例,用于控制媒體播放。
AVSession(Context context, String tag, PacMap sessionInfo) 構(gòu)造帶有附加會(huì)話信息的 AVSession 實(shí)例,用于控制媒體播放。
void setAVSessionCallback(AVSessionCallback callback) 設(shè)置回調(diào)函數(shù)來(lái)控制播放器,控制邏輯由應(yīng)用實(shí)現(xiàn)。如果 callback 為 null 則取消控制。
boolean setAVSessionAbility(IntentAgent ia) 給 AVSession 設(shè)置一個(gè)IntentAgent,用來(lái)啟動(dòng)用戶界面。
boolean setAVButtonReceiver(IntentAgent ia) 為媒體按鍵接收器設(shè)置一個(gè) IntentAgent,以便應(yīng)用結(jié)束后,可以通過(guò)媒體按鍵重新拉起應(yīng)用。
void enableAVSessionActive(boolean active) 設(shè)置是否激活媒體會(huì)話。當(dāng)會(huì)話準(zhǔn)備接收命令時(shí),將輸入?yún)?shù)設(shè)置為 true。如果會(huì)話停止接收命令,則設(shè)置為 false。
boolean isAVSessionActive() 查詢會(huì)話是否激活。
void sendAVSessionEvent(String event, PacMap options) 向所有訂閱此會(huì)話的控制器發(fā)送事件。
void release() 釋放資源,應(yīng)用播放完之后需調(diào)用。
AVToken getAVToken() 獲取應(yīng)用連接到會(huì)話的令牌。此令牌用于創(chuàng)建媒體播放控制器。
AVController getAVController() 獲取會(huì)話構(gòu)造時(shí)創(chuàng)建的控制器,方便應(yīng)用使用。
void setAVPlaybackState(AVPlaybackState state) 設(shè)置當(dāng)前播放狀態(tài)。
void setAVMetadata(AVMetadata avMetadata) 設(shè)置媒體資源元數(shù)據(jù)ohos.media.common.AVMetadata。
void setAVQueue(List queue) 設(shè)置播放隊(duì)列。
void setAVQueueTitle(CharSequence queueTitle) 設(shè)置播放隊(duì)列的標(biāo)題,UI會(huì)顯示此標(biāo)題。
void setOptions(PacMap options) 設(shè)置此會(huì)話關(guān)聯(lián)的附加數(shù)據(jù)。
AVCallerUserInfo getCurrentControllerInfo() 獲取發(fā)送當(dāng)前請(qǐng)求的媒體控制器信息。
接口名 描述
AVElement(AVDescription description, int flags) 構(gòu)造 AVElement 實(shí)例。
int getFlags() 獲取flags的值。
boolean isScannable() 判斷媒體是否可掃描,如:媒體有子節(jié)點(diǎn),則可繼續(xù)掃描獲取子節(jié)點(diǎn)內(nèi)容。
boolean isPlayable() 檢查媒體是否可播放。
AVDescription getAVDescription() 獲取媒體的詳細(xì)信息。
String getMediaId() 獲取媒體的id。

開(kāi)發(fā)步驟

使用 AVSession 媒體框架創(chuàng)建一個(gè)播放器示例,分為創(chuàng)建客戶端和創(chuàng)建服務(wù)端。

創(chuàng)建客戶端

在客戶端 AVClientAbility 中聲明 AVBrowser 和 AVController,并向服務(wù)端發(fā)送連接請(qǐng)求。

public class AVClientAbility extends Ability {
    // 媒體瀏覽器
    private AVBrowser avBrowser;
    // 媒體控制器
    private AVController avController;
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        // 用于指向媒體瀏覽器服務(wù)的包路徑和類名
        ElementName elementName = new ElementName("", "com.huawei.samples.audioplayer", "com.huawei.samples.audioplayer.AVService");
        // connectionCallback 在調(diào)用 avBrowser.connect 方法后進(jìn)行回調(diào)。
        avBrowser = new AVBrowser(context, elementName, connectionCallback, null);
        // avBrowser 發(fā)送對(duì)媒體瀏覽器服務(wù)的連接請(qǐng)求。
        avBrowser.connect();
        // 將媒體控制器注冊(cè)到 ability 以接收按鍵事件。
        AVController.setControllerForAbility(this, avController);
    }
}

AVConnectionCallback 回調(diào)接口中的方法為可選實(shí)現(xiàn),通常需要會(huì)在 onConnected 中訂閱媒體數(shù)據(jù)和創(chuàng)建媒體控制器 AVController。

// 發(fā)起連接(avBrowser.connect)后的回調(diào)方法實(shí)現(xiàn)
private AVConnectionCallback connectionCallback = new AVConnectionCallback() {
    @Override
    public void onConnected() {
        // 成功連接媒體瀏覽器服務(wù)時(shí)回調(diào)該方法,否則回調(diào) onConnectionFailed()。
        // 重復(fù)訂閱會(huì)報(bào)錯(cuò),所以先解除訂閱。
        avBrowser.unsubscribeByParentMediaId(avBrowser.getRootMediaId());
        // 第二個(gè)參數(shù) AVSubscriptionCallback,用于處理訂閱信息的回調(diào)。
        avBrowser.subscribeByParentMediaId(AV_ROOTavBrowser.getRootMediaId(), avSubscriptionCallback);
        AVToken token = avBrowser.getAVToken();
        avController = new AVController(AVClient.this, token); // AVController第一個(gè)參數(shù)為當(dāng)前類的context
        // 參數(shù) AVControllerCallback,用于處理服務(wù)端播放狀態(tài)及信息變化時(shí)回調(diào)。
        avController.setAVControllerCallback(avControllerCallback);
        // ...
    }
    // 其它回調(diào)方法(可選)
    // ...
};

通常在訂閱成功時(shí),在 AVSubscriptionCallback 回調(diào)接口 onAVElementListLoaded 中保存服務(wù)端回傳的媒體列表。

// 發(fā)起訂閱信息(avBrowser.subscribeByParentMediaId)后的回調(diào)方法實(shí)現(xiàn)
private AVSubscriptionCallback avSubscriptionCallback = new AVSubscriptionCallback() {
    @Override
    public void onAVElementListLoaded(String parentId, List children) {
        // 訂閱成功時(shí)回調(diào)該方法,parentID 為標(biāo)識(shí),children 為服務(wù)端回傳的媒體列表
        super.onAVElementListLoaded(parentId, children);
        list.addAll(children);
        // ...
    }
};

AVControllerCallback 回調(diào)接口中的方法均為可選方法,主要用于服務(wù)端播放狀態(tài)及信息的變化后對(duì)客戶端的回調(diào),客戶端可在這些方法中實(shí)現(xiàn)UI的刷新。

// 服務(wù)對(duì)客戶端的媒體數(shù)據(jù)或播放狀態(tài)變更后的回調(diào) 
 private AVControllerCallback     avControllerCallback = new  AVControllerCallback() {
    @Override
    public void onAVMetadataChanged(AVMetadata metadata) {
        // 當(dāng)服務(wù)端調(diào)用 avSession.setAVMetadata(avMetadata)時(shí),此方法會(huì)被回調(diào)。
        super.onAVMetadataChanged(metadata);
        AVDescription description = metadata.getAVDescription();
        String title = description.getTitle().toString();
        PixelMap pixelMap = description.getIcon();
        // ...
    }
    @Override
    public void onAVPlaybackStateChanged(AVPlaybackState playbackState) {
        // 當(dāng)服務(wù)端調(diào)用avSession.setAVPlaybackState(...)時(shí),此方法會(huì)被回調(diào)。
        super.onAVPlaybackStateChanged(playbackState);
        long position = playbackState.getCurrentPosition();
        // ...
    }
    // 其它回調(diào)方法(可選)
    // ...
};

完成以上實(shí)現(xiàn)后,則應(yīng)用可以在UI事件中調(diào)用avController的方法向服務(wù)端發(fā)送播放控制指令。

// 在 UI 播放與暫停按鈕的點(diǎn)擊事件中向服務(wù)端發(fā)送播放或暫停指令
public void toPlayOrPause() {
    switch (avController.getAVPlaybackState().getAVPlaybackState()) {
        case AVPlaybackState.PLAYBACK_STATE_NONE: {
            avController.getPlayControls().prepareToPlay();
            avController.getPlayControls().play();
            break;
        }
        case AVPlaybackState.PLAYBACK_STATE_PLAYING: {
            avController.getPlayControls().pause();
            break;
        }
        case AVPlaybackState.PLAYBACK_STATE_PAUSED: {
            avController.getPlayControls().play();
            break;
        }
        default: {
            // ...
        }
    }
}

其它播放控制根據(jù)業(yè)務(wù)是否需要實(shí)現(xiàn),比如:

avController.getPlayControls().playNext();
avController.getPlayControls().playPrevious();
avController.getPlayControls().playFastForward();
avController.getPlayControls().rewind();
avController.getPlayControls().seekTo(1000);
avController.getPlayControls().stop();
// ...

也可以主動(dòng)獲取媒體信息、播放狀態(tài)等數(shù)據(jù):

AVMetadata avMetadata = avController.getAVMetadata();
AVPlaybackState avPlaybackState = avController.getAVPlaybackState();
// ...

創(chuàng)建服務(wù)端

在服務(wù)端 AVService 中聲明 AVSession 和 Player。

public class AVService extends AVBrowserService {
    // 媒體會(huì)話
    private AVSession avSession;
    // 媒體播放器
    private Player player;

 
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        avSession = new AVSession(this, "AVService");
        setAVToken(avSession.getAVToken());
        // 設(shè)置 sessioncallback,用于響應(yīng)客戶端的媒體控制器發(fā)起的播放控制指令。
        avSession.setAVSessionCallback(avSessionCallback);
        // 設(shè)置播放狀態(tài)初始狀態(tài)為 AVPlaybackState.PLAYBACK_STATE_NONE。
        AVPlaybackState playbackState = new AVPlaybackState.Builder().setAVPlaybackState(AVPlaybackState.PLAYBACK_STATE_NONE, 0, 1.0f).build();
        avSession.setAVPlaybackState(playbackState);
        // 完成播放器的初始化,如果使用多個(gè)  Player,也可以在執(zhí)行播放時(shí)初始化。
        player = new Player(this);
    }
    @Override
    public AVBrowserRoot onGetRoot(String clientPackageName, int clientUid, PacMap rootHints) {
        // 響應(yīng)客戶端 avBrowser.connect()方法。若同意連接,則返回有效的AVBrowserRoot實(shí)例,否則返回null
        return new AVBrowserRoot(AV_ROOT, null);
    }
    @Override
    public void onLoadAVElementList(String parentId, AVBrowserResult result) {
         LogUtil.info(TAG, "onLoadChildren");
         // 響應(yīng)客戶端avBrowser.subscribeByParentMediaId(...)方法。
         // 先執(zhí)行該方法detachForRetrieveAsync() 
         result.detachForRetrieveAsync();
         // externalAudioItems緩存媒體文件,請(qǐng)開(kāi)發(fā)者自行實(shí)現(xiàn)。
         result.sendAVElementList(externalAudioItems.getAudioItems());
    }
    @Override
    public void onLoadAVElementList(String s, AVBrowserResult avBrowserResult, PacMap pacMap) {
         // 響應(yīng)客戶端avBrowser.subscribeByParentMediaId(String, PacMap, AVSubscriptionCallback)方法。
    }
    @Override
    public void onLoadAVElement(String s, AVBrowserResult avBrowserResult) {
        // 響應(yīng)客戶端avBrowser.getAVElement(String, AVElementCallback)方法。
    }
}

響應(yīng)客戶端的媒體控制器發(fā)起的播放控制指令的回調(diào)實(shí)現(xiàn)。

private AVSessionCallback avSessionCallback = new AVSessionCallback() {
    @Override
    public void onPlay() {
        super.onPlay();
        // 當(dāng)客戶端調(diào)用avController.getPlayControls().play()時(shí),該方法會(huì)被回調(diào)。
        // 響應(yīng)播放請(qǐng)求,開(kāi)始播放。
        if (avSession.getAVController().getAVPlaybackState().getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PAUSED) {
            if (player.play()) {
                AVPlaybackState playbackState = new AVPlaybackState.Builder().setAVPlaybackState(
                    AVPlaybackState.PLAYBACK_STATE_PLAYING, player.getCurrentTime(),
                    player.getPlaybackSpeed()).build();
                avSession.setAVPlaybackState(playbackState);
            }
        }
    }
    @Override
    public void onPause() {
        super.onPause();
        // 當(dāng)客戶端調(diào)用avController.getPlayControls().pause()時(shí),該方法會(huì)被回調(diào)。
        // 響應(yīng)暫停請(qǐng)求,暫停播放。
    }
    @Override
    public void onPlayNext() {
        super.onPlayNext();
        // 當(dāng)客戶端調(diào)用avController.getPlayControls().playNext()時(shí),該方法會(huì)被回調(diào)。
        // 響應(yīng)播放下一曲請(qǐng)求,通過(guò)avSession.setAVMetadata 設(shè)置下一曲曲目的信息。
        avSession.setAVMetadata(avNextMetadata);
    }
    // 重寫(xiě)以處理按鍵事件
    @Override
    public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
        KeyEvent ke = mediaButtonIntent.getParcelableParam(AVSession.PARAM_KEY_EVENT);
        if (ke == null) {
            LogUtil.error("onMediaButtonEvent", "getParcelableParam failed");
            return false;
        }
        if (ke.isKeyDown()) {
            // 只處理按鍵抬起事件
            return true;
        }

 
        switch (ke.getKeyCode()) {
            case KeyEvent.KEY_MEDIA_PLAY_PAUSE: {
                if (playbackState.getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PAUSED) {
                    onPlay();
                    break;
                }
                if (playbackState.getAVPlaybackState() == AVPlaybackState.PLAYBACK_STATE_PLAYING) {
                    onPause();
                    break;
                }
                break;
            }
            case KeyEvent.KEY_MEDIA_PLAY: {
                onPlay();
                break;
            }
            case KeyEvent.KEY_MEDIA_PAUSE: {
                onPause();
                break;
            }
            case KeyEvent.KEY_MEDIA_STOP: {
                onStop();
                break;
            }
            case KeyEvent.KEY_MEDIA_NEXT: {
                onPlayNext();
                break;
            }
            case KeyEvent.KEY_MEDIA_PREVIOUS: {
                onPlayPrevious();
                break;
            }
            default: {
                break;
            }
        }
        return true;
    }
    // 其它回調(diào)方法(可選)
    // ...
}

分享文章:創(chuàng)新互聯(lián)鴻蒙OS教程:鴻蒙OS媒體會(huì)話開(kāi)發(fā)指導(dǎo)
分享網(wǎng)址:http://www.5511xx.com/article/cogiihg.html