一、IM接入
常规集成
1.简单配置
api 'com.tencent.imsdk:imsdk-plus:5.6.1200'
ndk {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
-keep class com.tencent.imsdk.** { *; }
package com.z.zplay;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.tencent.imsdk.v2.V2TIMManager;
import com.tencent.imsdk.v2.V2TIMSDKConfig;
import com.tencent.imsdk.v2.V2TIMSDKListener;
import com.tencent.liteav.TXLiteAVCode;
import com.tencent.rtmp.TXLiveBase;
import com.tencent.trtc.TRTCCloud;
import com.tencent.trtc.TRTCCloudListener;
import com.z.zplay.im.GenerateTestUserSig;
public class IApplication extends Application {
private static IApplication instance;
private static String TAG = "IApplication";
public static IApplication instance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
initIM();
}
private void initIM() {
int sdkAppID = GenerateTestUserSig.SDKAPPID;
V2TIMSDKConfig sdkConfig = new V2TIMSDKConfig();
sdkConfig.setLogLevel(V2TIMSDKConfig.V2TIM_LOG_DEBUG);
V2TIMManager.getInstance().initSDK(this, sdkAppID, sdkConfig, new V2TIMSDKListener() {
@Override
public void onConnecting() {
Log.v(TAG,"onConnecting");
}
@Override
public void onConnectSuccess() {
Log.v(TAG,"onConnectSuccess");
}
@Override
public void onConnectFailed(int code, String error) {
Log.v(TAG,"onConnectFailed");
}
@Override
public void onKickedOffline() {
Log.v(TAG,"onKickedOffline");
}
@Override
public void onUserSigExpired() {
Log.v(TAG,"onUserSigExpired");
}
});
}
}
2.单聊、群聊
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".im.IMLoginActivity">
<EditText
android:id="@+id/et_userid"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="user1" />
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录" />
<Button
android:id="@+id/btn_to_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录后开直播" />
<Button
android:id="@+id/btn_look_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录后看直播" />
<EditText
android:id="@+id/et_msg"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入消息内容" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_to_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="请输入对方userid"
android:text="user" />
<Button
android:id="@+id/btn_c2c"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="单聊发送" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp">
<Button
android:id="@+id/btn_create_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="创建群组" />
<TextView
android:id="@+id/tv_group_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="群组ID" />
<ImageView
android:id="@+id/iv_code"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_launcher_background" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_join"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="请输入群组id" />
<Button
android:id="@+id/btn_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="扫一扫" />
<Button
android:id="@+id/btn_join"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加入群组" />
</LinearLayout>
<Button
android:id="@+id/btn_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="群聊发送" />
<Button
android:id="@+id/btn_custom_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点赞" />
<TextView
android:id="@+id/tv_msg"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="接收消息" />
</LinearLayout>
package com.z.zplay.im
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import com.king.zxing.util.CodeUtils
import com.tencent.imsdk.v2.*
import com.z.zplay.CaptureCustomActivity
import com.z.zplay.CopyUtils
import com.z.zplay.R
import com.z.zplay.ValueEvent
import com.z.zplay.imlives.TAnchorActivity
import com.z.zplay.imlives.TAudienceActivity
import kotlinx.android.synthetic.main.activity_imlogin.*
import kotlinx.android.synthetic.main.activity_imlogin.btn_scan
import kotlinx.android.synthetic.main.activity_main.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class IMLoginActivity : AppCompatActivity() {
val TAG = "IMLoginActivity"
var userID = ""
var userSig = ""
companion object {
val USER_ID = "userid"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_imlogin)
V2TIMManager.getInstance().addSimpleMsgListener(object : V2TIMSimpleMsgListener() {
override fun onRecvC2CTextMessage(
msgID: String?,
sender: V2TIMUserInfo?,
text: String?
) {
super.onRecvC2CTextMessage(msgID, sender, text)
Log.v(TAG, "发送者:" + sender?.userID)
Log.v(TAG, "消息id:$msgID,消息:$text")
tv_msg.text = text
}
override fun onRecvGroupTextMessage(
msgID: String?,
groupID: String?,
sender: V2TIMGroupMemberInfo?,
text: String?
) {
super.onRecvGroupTextMessage(msgID, groupID, sender, text)
Log.v(TAG, "发送者:" + sender?.userID)
Log.v(TAG, "消息id:$msgID,消息:$text")
tv_msg.text = text
}
override fun onRecvGroupCustomMessage(
msgID: String?,
groupID: String?,
sender: V2TIMGroupMemberInfo?,
customData: ByteArray?
) {
super.onRecvGroupCustomMessage(msgID, groupID, sender, customData)
Log.v(TAG, "发送者:" + sender?.userID)
Log.v(TAG, "消息id:$msgID,消息:${customData?.toString(Charsets.UTF_8)}")
tv_msg.text = customData?.toString(Charsets.UTF_8)
}
})
btn_login.setOnClickListener {
userID = et_userid!!.text.toString()
userSig = GenerateTestUserSig.genTestUserSig(userID)
V2TIMManager.getInstance().login(userID, userSig, object : V2TIMCallback {
override fun onSuccess() {
Toast.makeText(this@IMLoginActivity, "登录成功", Toast.LENGTH_SHORT).show()
}
override fun onError(code: Int, desc: String) {
val log = "登录失败code:$code,desc:$desc"
Log.v("login", log)
Toast.makeText(this@IMLoginActivity, log, Toast.LENGTH_SHORT).show()
}
})
}
btn_to_live.setOnClickListener {
var int = Intent(this@IMLoginActivity, TAnchorActivity::class.java)
int.putExtra(USER_ID,userID)
startActivity(int)
}
btn_look_live.setOnClickListener {
var int = Intent(this@IMLoginActivity, TAudienceActivity::class.java)
int.putExtra(USER_ID,userID)
startActivity(int)
}
btn_c2c.setOnClickListener {
V2TIMManager.getInstance().sendC2CTextMessage(
et_msg.text.toString(),
et_to_user.text.toString(),
object : V2TIMValueCallback<V2TIMMessage> {
override fun onSuccess(t: V2TIMMessage?) {
Toast.makeText(this@IMLoginActivity, "发送消息成功", Toast.LENGTH_SHORT).show()
}
override fun onError(code: Int, desc: String?) {
Toast.makeText(this@IMLoginActivity, "发送消息失败", Toast.LENGTH_SHORT).show()
}
})
}
btn_create_group.setOnClickListener {
V2TIMManager.getInstance()
.createGroup("AVChatRoom", null, "篮球群", object : V2TIMValueCallback<String> {
override fun onSuccess(t: String?) {
Log.v(TAG, "创建群成功:$t")
tv_group_id.text = t
et_join.setText(t)
var bitmap = CodeUtils.createQRCode(t, 200)
iv_code.setImageBitmap(bitmap)
}
override fun onError(code: Int, desc: String?) {
Log.v(TAG, "创建群失败:$code,$desc")
}
})
}
btn_scan.setOnClickListener {
startActivity(Intent(this, CaptureCustomActivity::class.java))
}
tv_group_id.setOnClickListener {
CopyUtils.clip(this, tv_group_id.text.toString())
}
btn_join.setOnClickListener {
V2TIMManager.getInstance().joinGroup(
et_join.text.toString(),
"大家好,我是" + et_userid.text.toString(),
object : V2TIMCallback {
override fun onSuccess() {
Toast.makeText(this@IMLoginActivity, "入群成功", Toast.LENGTH_SHORT).show()
}
override fun onError(code: Int, desc: String?) {
Toast.makeText(this@IMLoginActivity, "入群失败:$code,$desc", Toast.LENGTH_SHORT)
.show()
}
})
}
btn_group.setOnClickListener {
V2TIMManager.getInstance().sendGroupTextMessage(
et_msg.text.toString(),
et_join.text.toString(),
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
object : V2TIMValueCallback<V2TIMMessage> {
override fun onSuccess(t: V2TIMMessage?) {
Toast.makeText(this@IMLoginActivity, "发送消息成功", Toast.LENGTH_SHORT).show()
}
override fun onError(code: Int, desc: String?) {
Toast.makeText(
this@IMLoginActivity,
"发送消息失败$code,$desc",
Toast.LENGTH_SHORT
).show()
}
})
}
btn_custom_group.setOnClickListener {
var upmsg = "{ \"command\": \"favor\", \"value\": 101 }"
V2TIMManager.getInstance()
.sendGroupCustomMessage(upmsg.toByteArray(Charsets.UTF_8), et_join.text.toString(),
V2TIMMessage.V2TIM_PRIORITY_NORMAL,
object : V2TIMValueCallback<V2TIMMessage> {
override fun onSuccess(t: V2TIMMessage?) {
Toast.makeText(this@IMLoginActivity, "发送消息成功", Toast.LENGTH_SHORT)
.show()
}
override fun onError(code: Int, desc: String?) {
Toast.makeText(
this@IMLoginActivity,
"发送消息失败$code,$desc",
Toast.LENGTH_SHORT
).show()
}
})
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onValueEvent(event: ValueEvent) {
et_join.setText(event.value.toString())
}
override fun onStart() {
super.onStart()
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this)
}
}
override fun onDestroy() {
super.onDestroy()
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this)
}
}
}
GenerateTestUserSig可参考 或者腾讯的demo基本都有。
二、实时音视频 TRTC
跑通直播模式
简单配置
implementation 'com.tencent.liteav:LiteAVSDK_Professional:latest.release'
ndk {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
主播页面
package com.z.zplay.zhibo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.tencent.liteav.TXLiteAVCode;
import com.tencent.rtmp.ui.TXCloudVideoView;
import com.tencent.trtc.TRTCCloud;
import com.tencent.trtc.TRTCCloudDef;
import com.tencent.trtc.TRTCCloudListener;
import com.z.zplay.R;
import com.z.zplay.im.GenerateTestUserSig;
import static com.tencent.trtc.TRTCCloudDef.TRTC_VIDEO_RENDER_MODE_FIT;
public class AnchorActivity extends AppCompatActivity {
private EditText et_userid;
private EditText et_roomid;
private Button btn_to_room;
private Button btn_exit;
private TRTCCloud mTRTCCloud;
private TXCloudVideoView pusher_tx_cloud_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_anchor);
initRTC();
et_userid = findViewById(R.id.et_userid);
et_roomid = findViewById(R.id.et_roomid);
btn_to_room = findViewById(R.id.btn_to_room);
btn_exit = findViewById(R.id.btn_exit);
pusher_tx_cloud_view = findViewById(R.id.pusher_tx_cloud_view);
btn_to_room.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
params.sdkAppId = GenerateTestUserSig.SDKAPPID;
params.userId = et_userid.getText().toString();
params.userSig = GenerateTestUserSig.genTestUserSig(params.userId);
params.roomId = Integer.parseInt(et_roomid.getText().toString());
mTRTCCloud.startLocalPreview(true, pusher_tx_cloud_view);
mTRTCCloud.setLocalViewFillMode(TRTC_VIDEO_RENDER_MODE_FIT);
TRTCCloudDef.TRTCVideoEncParam encParam = new TRTCCloudDef.TRTCVideoEncParam();
encParam.videoResolution = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_960_540;
encParam.videoFps = 15;
encParam.videoBitrate = 1200;
encParam.videoResolutionMode = TRTCCloudDef.TRTC_VIDEO_RESOLUTION_MODE_PORTRAIT;
mTRTCCloud.setVideoEncoderParam(encParam);
mTRTCCloud.startLocalAudio();
params.role = TRTCCloudDef.TRTCRoleAnchor;
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
});
btn_exit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mTRTCCloud.exitRoom();
}
});
}
private void initRTC() {
mTRTCCloud = TRTCCloud.sharedInstance(getApplicationContext());
mTRTCCloud.setListener(new TRTCCloudListener() {
@Override
public void onEnterRoom(long result) {
if (result > 0) {
Toast.makeText(AnchorActivity.this, "进房成功,总计耗时" + result + "ms", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(AnchorActivity.this, "进房失败,错误码:" + result, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onExitRoom(int reason) {
Toast.makeText(AnchorActivity.this, "退出房间" + reason, Toast.LENGTH_SHORT).show();
}
@Override
public void onError(int errCode, String errMsg, Bundle extraInfo) {
Toast.makeText(AnchorActivity.this, "onError: " + errMsg + "[" + errCode + "]", Toast.LENGTH_SHORT).show();
if (errCode == TXLiteAVCode.ERR_ROOM_ENTER_FAIL) {
mTRTCCloud.exitRoom();
}
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".zhibo.AnchorActivity">
<EditText
android:id="@+id/et_userid"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="user1" />
<EditText
android:id="@+id/et_roomid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入房间id" />
<Button
android:id="@+id/btn_to_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="主播进入" />
<Button
android:id="@+id/btn_exit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="主播销毁" />
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/pusher_tx_cloud_view"
android:layout_width="match_parent"
android:layout_height="500dp" />
</LinearLayout>
观众页面
package com.z.zplay.zhibo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.tencent.liteav.TXLiteAVCode;
import com.tencent.rtmp.ui.TXCloudVideoView;
import com.tencent.trtc.TRTCCloud;
import com.tencent.trtc.TRTCCloudDef;
import com.tencent.trtc.TRTCCloudListener;
import com.z.zplay.R;
import com.z.zplay.im.GenerateTestUserSig;
public class AudienceActivity extends AppCompatActivity {
private TRTCCloud mTRTCCloud;
private EditText et_userid;
private EditText et_zb_userid;
private EditText et_roomid;
private Button btn_to_room;
private Button btn_exit;
private TXCloudVideoView tx_cloud_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audience);
et_userid = findViewById(R.id.et_userid);
et_zb_userid = findViewById(R.id.et_zb_userid);
et_roomid = findViewById(R.id.et_roomid);
btn_to_room = findViewById(R.id.btn_to_room);
btn_exit = findViewById(R.id.btn_exit);
tx_cloud_view = findViewById(R.id.tx_cloud_view);
initRTC();
btn_to_room.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();
params.sdkAppId = GenerateTestUserSig.SDKAPPID;
params.userId = et_userid.getText().toString();
params.userSig = GenerateTestUserSig.genTestUserSig(params.userId);
params.roomId = Integer.parseInt(et_roomid.getText().toString());
params.role = TRTCCloudDef.TRTCRoleAudience;
mTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_LIVE);
}
});
btn_exit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mTRTCCloud.exitRoom();
}
});
}
private void initRTC() {
mTRTCCloud = TRTCCloud.sharedInstance(getApplicationContext());
mTRTCCloud.setListener(new TRTCCloudListener() {
@Override
public void onEnterRoom(long result) {
if (result > 0) {
Toast.makeText(AudienceActivity.this, "进房成功,总计耗时" + result + "ms", Toast.LENGTH_SHORT).show();
mTRTCCloud.startRemoteView(et_zb_userid.getText().toString(), TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_BIG, tx_cloud_view);
} else {
Toast.makeText(AudienceActivity.this, "进房失败,错误码:" + result, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(int errCode, String errMsg, Bundle extraInfo) {
Toast.makeText(AudienceActivity.this, "onError: " + errMsg + "[" + errCode + "]", Toast.LENGTH_SHORT).show();
if (errCode == TXLiteAVCode.ERR_ROOM_ENTER_FAIL) {
mTRTCCloud.exitRoom();
}
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".zhibo.AnchorActivity">
<EditText
android:id="@+id/et_userid"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="user88" />
<EditText
android:id="@+id/et_zb_userid"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入主播的userid"
/>
<EditText
android:id="@+id/et_roomid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入房间id" />
<Button
android:id="@+id/btn_to_room"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="观众进入" />
<Button
android:id="@+id/btn_exit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="观众退出" />
<com.tencent.rtmp.ui.TXCloudVideoView
android:id="@+id/tx_cloud_view"
android:layout_width="match_parent"
android:layout_height="500dp" />
</LinearLayout>
|