主頁 > 移動端開發 > Android MediaPlayer播放 聽筒外放切換

Android MediaPlayer播放 聽筒外放切換

2021-11-09 08:24:30 移動端開發

Android MediaPlayer播放 聽筒外放切換,通過注冊監聽,來判斷是否靠近聽筒,

結合mediaplayer坐音頻播放,Android hardware搞一個根據光感聽筒外放切換,
MediaManager是播放器構建模式,維護了一個MediaPlayer,用來重新處理播放器,

MediaManager.builder()
                        .setContext(MainActivity.this)
                        .setDebugModel(true)
                        .setMediaListener(new MediaCallBack() {
                            @Override
                            public void progress(int i, int max) {

                            }

                            @Override
                            public void prepare(int duration, String time) {

                            }

                            @Override
                            public void start() {

                            }

                            @Override
                            public void end() {

                            }

                            @Override
                            public void stop() {

                            }
                        })
                        .setUrl("https://96.f.1ting.com/local_to_cube_202004121813/96kmp3/2020/09/21/21e_wc/01.mp3")
                        .build();

開始播放

                MediaManager.start();

停止

                MediaManager.stop();

是否正在播放

                MediaManager.isPlaying();

暫停

                MediaManager.pause();

繼續

                MediaManager.resume();

銷毀當前的mediaplayer destory時候呼叫

                MediaManager.removeAll();

AudioManager

Android為我們提供的(音量大小控制)的API: AudioManager(音頻管理器)了,該類位于Android.Media包下,提供了音量控制與鈴聲模式相關操作,

獲得AudioManager物件實體

AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);

PowerManager

Android系統為我們提供的電源管理的一個API,其相關介面與設備電池的續航能力有很大的關聯, 官方也說了,除非是迫不得已吧,不然的話,應該盡量避免使用這個類,并且使用完以后一定要及時釋放,所謂的電源管理包括:CPU運行,鍵盤或者螢屏亮起來!核心其實就是wakelock鎖機制,只要我們拿著這個鎖, 那么系統就無法進入休眠狀態,可以給用戶態程式或內核獲取到,鎖可以是:”有超時的“或者 “沒有超時“,超時的鎖到時間后會自動解鎖,如果沒有了鎖或超時,內核會啟動休眠機制來進入休眠,

添加權限

    <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>

獲取PowerManager物件實體

 powerManager = (PowerManager) getActivity().getSystemService(POWER_SERVICE);

整體的代碼如下:


/**
 * Created by SHICHENG
 * <p>
 * Time on 2021/11/08
 */
public class AudioSensorBinder implements LifecycleObserver, SensorEventListener {

    public final String TAG = this.getClass().getSimpleName();

    private final AudioManager audioManager;
    private final PowerManager powerManager;

    @Nullable
    private WeakReference<AppCompatActivity> activity;
    private SensorManager sensorManager;
    private Sensor sensor;
    private PowerManager.WakeLock wakeLock;

    @RequiresApi(api = Build.VERSION_CODES.M)
    public AudioSensorBinder(@Nullable AppCompatActivity mActivity) {
        this.activity = new WeakReference<>(mActivity);
        //可以監聽生命周期
        if (getActivity()!=null){
            getActivity().getLifecycle().addObserver(this);
        }
        audioManager = (AudioManager) getActivity().getSystemService(AUDIO_SERVICE);
        powerManager = (PowerManager) getActivity().getSystemService(POWER_SERVICE);
        registerProximitySensorListener();
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume() {

    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        sensorManager.unregisterListener(this);
        sensorManager = null;
        wakeLock = null;
        activity = null;
    }
    /**
     * 注冊距離感應器監聽器,監測用戶是否靠近手機聽筒
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void registerProximitySensorListener() {
        if ( getActivity() == null) {
            return;
        }
        sensorManager = (SensorManager) getActivity().getSystemService(SENSOR_SERVICE);
        if (sensorManager == null) {
            return;
        }
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
        sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
    }


    private AppCompatActivity getActivity() {
        if (activity != null) {
            return activity.get();
        }
        return null;
    }


    @Override
    public void onSensorChanged(SensorEvent event) {
        if (audioManager == null) {
            return;
        }
        if (isHeadphonesPlugged()) {
            // 如果耳機已插入,設定距離傳感器失效
            return;
        }
        if (true) {
            Log.i(TAG, "onSensorChanged: " + MediaManager.isPlaying() + " event.values[0]: " + event.values[0]);
        }
        if (MediaManager.isPlaying()) {
            // 如果音頻正在播放
            float distance = event.values[0];
            if (distance >= sensor.getMaximumRange()) {
                // 用戶遠離聽筒,音頻外放,亮屏
                changeToSpeaker();
                if (true) {
                    Log.i(TAG, "onSensorChanged: 外放");
                }
            } else {
                MediaManager.resume();
                // 用戶貼近聽筒,切換音頻到聽筒輸出,并且熄屏防誤觸
                changeToReceiver();
                if (true) {
                    Log.i(TAG, "onSensorChanged: 聽筒");
                }
                audioManager.setSpeakerphoneOn(false);
            }
        } else {
            // 音頻播放完了
            changeToSpeaker();
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @SuppressLint("WrongConstant")
    private boolean isHeadphonesPlugged() {
        if (audioManager == null) {
            return false;
        }
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
            for (AudioDeviceInfo deviceInfo : audioDevices) {
                if (deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
                        || deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
                    return true;
                }
            }
            return false;
        } else {
            return audioManager.isWiredHeadsetOn();
        }
    }

    /**
     * 切換到外放
     */
    public void changeToSpeaker() {
        setScreenOn();
        if (audioManager == null) {
            return;
        }
        audioManager.setMode(AudioManager.MODE_NORMAL);
        audioManager.setSpeakerphoneOn(true);
    }

    /**
     * 切換到耳機模式
     */
    public void changeToHeadset() {
        if (audioManager == null) {
            return;
        }
        audioManager.setSpeakerphoneOn(false);
    }

    /**
     * 切換到聽筒
     */
    public void changeToReceiver() {
        setScreenOff();
        if (audioManager == null) {
            return;
        }
        audioManager.setSpeakerphoneOn(false);
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
    }

    private void setScreenOff() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            Log.i(TAG, "setScreenOff: 熄滅螢屏");
            if (wakeLock == null) {
                wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
            }
            wakeLock.acquire(10 * 60 * 1000L /*10 minutes*/);
        }
    }

    private void setScreenOn() {
        if (wakeLock != null) {
            wakeLock.setReferenceCounted(false);
            wakeLock.release();
            wakeLock = null;
        }
    }
}

MediaManager


/**
 * Created by SHICHENG
 * <p>
 * Time on 2021/11/08
 */
public class MediaManager {

    private static MediaManagerBuilder mediaManagerBuilder;

    public static MediaManagerBuilder builder() {
        mediaManagerBuilder = new MediaManagerBuilder();
        return mediaManagerBuilder;
    }

    public static void start(){
        mediaManagerBuilder.start();
    }

    public static boolean isPlaying(){
        if (mediaManagerBuilder!=null){
            return mediaManagerBuilder.isPlaying();
        }
        return false;
    }

    public static void stop(){
        if (mediaManagerBuilder!=null){
            mediaManagerBuilder.stop();
        }
    }

    public static void pause(){
        if (mediaManagerBuilder!=null){
            mediaManagerBuilder.pause();
        }
    }

    public static void resume(){
        if (mediaManagerBuilder!=null){
            mediaManagerBuilder.resume();
        }
    }
    public static void removeAll(){
        if (mediaManagerBuilder!=null){
            mediaManagerBuilder.removeAll();
        }
    }

    public static class MediaManagerBuilder{

        public final String TAG = this.getClass().getSimpleName();
        private Handler handler = new Handler();
        private boolean isSeekBarChanging;//互斥變數,防止進度條與定時器沖突,

        private Context context;
        private MediaConfig config;
        private MediaCallBack mediaListener;
        private MediaPlayer mediaPlayer;
        private boolean DEBUG = false;
        private SimpleDateFormat format;
        private Timer timer;
        private TimerTask timerTask;
        private SeekBar seekBar;

        private MediaManagerBuilder() {
            this.config = new MediaConfig();
            this.mediaPlayer = new MediaPlayer();
            this.format = new SimpleDateFormat("mm:ss");
        }

        /**
         * 當前Activity的背景關系
         *
         * @param context
         * @return
         */

        public MediaManagerBuilder setContext(Context context){
            this.context = context;
            return this;
        }

        /**
         * 設定MediaPlayer Url鏈接
         *
         * @param url
         * @return
         */
        public MediaManagerBuilder setUrl(String url){
            this.config.url = url;
            return this;
        }

        /**
         * 設定播放進度監聽回呼
         *
         * @param mediaListener
         * @return
         */
        public MediaManagerBuilder setMediaListener(MediaCallBack mediaListener){
            this.mediaListener = mediaListener;
            return this;
        }

        /**
         * 設定是否是debug
         *
         * @param b
         * @return
         */
        public MediaManagerBuilder setDebugModel(boolean b){
            this.DEBUG = b;
            return this;
        }

        /**
         * 設定進度條
         */
        public MediaManagerBuilder setProgressSeek(SeekBar seek){
            this.seekBar = seek;
            return this;
        }


        /**
         * 初始化MediaPlayer
         */

        public MediaManagerBuilder build(){
            Uri uri = Uri.parse(config.url);
            //播放器不能為空
            if (mediaPlayer!=null){
                //如果是正在播放的狀態 需要暫停上一個
                if (mediaPlayer.isPlaying()){
                    mediaPlayer.stop();
                }
                //重置播放器
                mediaPlayer.release();
            }
            //創建新的播放器
            mediaPlayer = new MediaPlayer();
            try {
                mediaPlayer.setDataSource(config.url); //指定音頻檔案的路徑
                mediaPlayer.prepare();//讓mediaplayer進入準備狀態
                mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        if (seekBar!=null){
                            seekBar.setMax(mediaPlayer.getDuration());
                        }
                        mediaListener.prepare(mediaPlayer.getDuration(),format.format(mediaPlayer.getDuration()) + "");
                    }
                });
                // 監聽音頻播放完的代碼,實作音頻的自動回圈播放
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer arg0) {
                        mediaListener.end();
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
            timerTask = new TimerTask() {

                Runnable updateUI = new Runnable() {
                    @Override
                    public void run() {
                        if (mediaPlayer != null && mediaPlayer.getCurrentPosition() != -1) {
                            mediaListener.progress(mediaPlayer.getCurrentPosition(), mediaPlayer.getDuration());
                        }
                    }
                };

                @Override
                public void run() {
                    if (!isSeekBarChanging) {
                        if (seekBar!=null){
                            seekBar.setProgress(mediaPlayer.getCurrentPosition());
                        }
                        handler.post(updateUI);
                    }

                }
            };
            if (seekBar!=null){
                seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {
                        isSeekBarChanging = true;
                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {
                        isSeekBarChanging = false;
                        mediaPlayer.seekTo(seekBar.getProgress());
                    }
                });
            }
            return this;
        }


        /**
         * 開始播放
         */
        private void start(){
            //開始播放
            mediaPlayer.start();
            if (seekBar!=null){
                mediaPlayer.seekTo(seekBar.getProgress());
            }
            if (DEBUG){
                Log.i(TAG, "start: media start");
            }
            //監聽播放時回呼函式
            timer = new Timer();
            timer.schedule(timerTask,0,50);
        }

        /**
         * 停止播放
         */
        private void stop(){
            //播放器不能為空  為空終止
            if (mediaPlayer == null){
                return;
            }
            mediaPlayer.stop();
            if (DEBUG){
                Log.i(TAG, "start: media stop");
            }
        }

        /**
         * 暫停播放
         */
        private void pause(){
            //播放器不能為空  為空終止
            if (mediaPlayer == null){
                return;
            }
            mediaPlayer.pause();
            if (DEBUG){
                Log.i(TAG, "start: media pause");
            }
        }

        /**
         * 繼續播放
         */
        private void resume(){
            //播放器不能為空  為空終止
            if (mediaPlayer == null){
                return;
            }
            mediaPlayer.start();
            if (DEBUG){
                Log.i(TAG, "start: media resume");
            }
        }

        /**
         * 是否是播放中
         */
        private boolean isPlaying(){
            if (mediaPlayer!=null){
                return mediaPlayer.isPlaying();
            }
            return false;
        }

        /**
         * 移除所有 清除記憶體
         */
        public void removeAll(){
            isSeekBarChanging = true;
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
            if (mediaPlayer != null) {
                mediaPlayer.stop();
                mediaPlayer.release();
                mediaPlayer = null;
            }
        }



    }




}

Demo gitee

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/353439.html

標籤:其他

上一篇:Autojs.pro 7.0 - 免root 連點器

下一篇:[RK3568 Android11] 教程之parameter新建磁區

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more