如何在Android上自定义最新版Mesibo音视频通话UI?
解决Mesibo 2.7.18版本自定义通话UI的方案
Mesibo在2.x后期版本中重构了音视频通话的UI组件,旧文档里的MesiboCall.MesiboCallListener、MesiboIncomingAudioCallFragment等类确实已被替换。以下是基于2.7.18版本实现自定义通话UI的具体步骤和示例代码:
核心思路
新版本通过MesiboCallManager管理通话,自定义UI需要实现新版本的通话监听接口,并自行创建通话Activity/Fragment来控制布局、按钮逻辑和音视频渲染。
1. 实现新版通话监听接口MesiboCallListenerV2
这个接口替代了旧版的MesiboCall.MesiboCallListener,用于接收通话状态、音视频轨道等关键回调:
public class CustomCallListener implements MesiboCallListenerV2 { private final CustomCallActivity mActivity; public CustomCallListener(CustomCallActivity activity) { mActivity = activity; } @Override public void onCallStatus(MesiboCall call, int status, int reason) { // 处理通话状态变化:响铃、连接中、通话中、结束等 mActivity.updateCallStatus(status); } @Override public void onCallTrack(MesiboCall call, int type, Object track) { // 获取音视频轨道,绑定到本地/远端视图 if (type == MesiboCall.TYPE_VIDEO_LOCAL) { mActivity.bindLocalVideo((SurfaceView) track); } else if (type == MesiboCall.TYPE_VIDEO_REMOTE) { mActivity.bindRemoteVideo((SurfaceView) track); } } // 按需实现其他回调方法(音频静音状态、摄像头切换、通话统计等) @Override public void onCallAudio(MesiboCall call, boolean enabled) {} @Override public void onCallVideo(MesiboCall call, boolean enabled) {} @Override public void onCallRemoteVideo(MesiboCall call, boolean enabled) {} @Override public void onCallCameraSwitch(MesiboCall call, int camera) {} @Override public void onCallStats(MesiboCall call, MesiboCallStats stats) {} @Override public void onCallData(MesiboCall call, byte[] data) {} }
2. 创建自定义通话布局
自行设计通话界面的布局(示例activity_custom_call.xml),包含视频渲染视图和控制按钮:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000"> <!-- 远端视频全屏视图 --> <SurfaceView android:id="@+id/remote_video" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 本地视频小窗口 --> <SurfaceView android:id="@+id/local_video" android:layout_width="120dp" android:layout_height="160dp" android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:layout_margin="16dp" /> <!-- 底部控制按钮栏 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" android:gravity="center" android:padding="16dp"> <ImageButton android:id="@+id/btn_mute" android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/ic_mute_off" android:background="@drawable/call_button_round" /> <ImageButton android:id="@+id/btn_switch_camera" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginHorizontal="32dp" android:src="@drawable/ic_switch_camera" android:background="@drawable/call_button_round" /> <ImageButton android:id="@+id/btn_hangup" android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/ic_hangup" android:background="@drawable/call_button_red_round" /> </LinearLayout> </RelativeLayout>
3. 实现自定义通话Activity逻辑
将布局、监听和通话控制逻辑绑定:
public class CustomCallActivity extends AppCompatActivity { private MesiboCall mCurrentCall; private CustomCallListener mCallListener; private SurfaceView mLocalVideo, mRemoteVideo; private ImageButton mMuteBtn, mSwitchCameraBtn, mHangupBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_call); // 初始化视图 mLocalVideo = findViewById(R.id.local_video); mRemoteVideo = findViewById(R.id.remote_video); mMuteBtn = findViewById(R.id.btn_mute); mSwitchCameraBtn = findViewById(R.id.btn_switch_camera); mHangupBtn = findViewById(R.id.btn_hangup); // 获取当前通话实例 mCurrentCall = MesiboCallManager.getInstance().getActiveCall(); if (mCurrentCall == null) { finish(); return; } // 设置通话监听 mCallListener = new CustomCallListener(this); mCurrentCall.setListener(mCallListener); // 绑定按钮点击事件 mMuteBtn.setOnClickListener(v -> toggleMute()); mSwitchCameraBtn.setOnClickListener(v -> mCurrentCall.switchCamera()); mHangupBtn.setOnClickListener(v -> hangupCall()); } // 切换音频静音状态 private void toggleMute() { boolean isMuted = mCurrentCall.isAudioMuted(); mCurrentCall.setAudioMuted(!isMuted); mMuteBtn.setImageResource(isMuted ? R.drawable.ic_mute_off : R.drawable.ic_mute_on); } // 挂断通话 private void hangupCall() { mCurrentCall.hangup(); finish(); } // 更新通话状态UI public void updateCallStatus(int status) { switch (status) { case MesiboCall.STATUS_RINGING: // 显示"对方正在响铃"提示 break; case MesiboCall.STATUS_CONNECTED: // 显示"通话中"提示 break; case MesiboCall.STATUS_ENDED: finish(); break; } } // 绑定本地视频轨道到视图 public void bindLocalVideo(SurfaceView track) { mLocalVideo.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { mCurrentCall.setLocalSurface(holder.getSurface()); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} }); } // 绑定远端视频轨道到视图 public void bindRemoteVideo(SurfaceView track) { mRemoteVideo.getHolder().addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { mCurrentCall.setRemoteSurface(holder.getSurface()); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} @Override public void surfaceDestroyed(SurfaceHolder holder) {} }); } @Override protected void onDestroy() { super.onDestroy(); if (mCurrentCall != null) { mCurrentCall.setListener(null); } } }
4. 接管来电/去电的界面跳转
在应用初始化时,通过MesiboCallManager监听通话请求,启动自定义界面而非SDK默认界面:
// 在MainActivity或Application的onCreate中添加 MesiboCallManager.getInstance().addListener(new MesiboCallManager.CallListener() { @Override public boolean onIncomingCall(MesiboCall call) { // 启动自定义来电界面 Intent intent = new Intent(MainActivity.this, CustomCallActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return true; // 返回true表示自行处理,不使用SDK默认UI } @Override public boolean onOutgoingCall(MesiboCall call) { // 启动自定义去电界面 Intent intent = new Intent(MainActivity.this, CustomCallActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return true; } });
注意事项
- 权限:确保已申请并动态获取
CAMERA、RECORD_AUDIO、INTERNET权限。 - 测试:必须在真机上测试,模拟器通常不支持摄像头和音频输入。
- 异常处理:需处理通话实例为空、权限被拒绝等异常场景,避免崩溃。
内容的提问来源于stack exchange,提问作者Eko Yulianto
相关产品推荐
相关产品推荐

