製品アップデート情報
Tencent Cloudオーディオビデオ端末SDKの再生アップグレードおよび承認チェック追加に関するお知らせ
TRTCアプリケーションのサブスクリプションパッケージサービスのリリースに関する説明について





dependencies {// TRTC Lite版SDK、TRTCとライブ再生の2つの機能を含みます。implementation 'com.tencent.liteav:LiteAVSDK_TRTC:latest.release'// Chat SDKを追加、最新のバージョン番号を記入することがお勧めです。implementation 'com.tencent.imsdk:imsdk-plus:Version number'// Quicプラグインを追加する必要がある場合、次の行のコメントを解除(注意:プラグインのバージョン番号とChat SDKのバージョン番号が同じである必要がある)// implementation 'com.tencent.imsdk:timquic-plugin:Version number'}
defaultConfig {ndk {abiFilters "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.RECORD_AUDIO" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /><uses-permission android:name="android.permission.BLUETOOTH" />
targetSdkVersionが31または対象デバイスがAndroid 12以上のシステムバージョンに関連している場合、Bluetooth機能を正常に使用するため、公式にはコード内でandroid.permission.BLUETOOTH_CONNECT権限を動的な申請する必要があります。詳細はBluetooth権限を参照してください。-keep class com.tencent.** { *; }

// イベントリスナーを追加V2TIMManager.getInstance().addIMSDKListener(imSdkListener);// Chat SDKを初期化し、このインターフェースを呼び出した後、すぐにログインインターフェースを呼び出すことができます。V2TIMManager.getInstance().initSDK(context, sdkAppID, null);// SDK初期化後にはいくつかのイベントが発生します。例えば、接続状態、ログインチケットの有効期限切れなど。private V2TIMSDKListener imSdkListener = new V2TIMSDKListener() {@Overridepublic void onConnecting() {Log.d(TAG, "Chat SDKはTencent Cloudサーバーに接続中です");}@Overridepublic void onConnectSuccess() {Log.d(TAG, "Chat SDKはTencent Cloudサーバーへの接続に成功しました");}};// イベントリスナーを削除V2TIMManager.getInstance().removeIMSDKListener(imSdkListener);// Chat SDKの初期化を解除しますV2TIMManager.getInstance().unInitSDK();
// RTC Engine SDK インスタンスの作成(シングルトンパターン)TRTCCloud mTRTCCloud = TRTCCloud.sharedInstance(context);// イベントリスナーを設定するmTRTCCloud.setListener(trtcSdkListener);// SDKからの各種イベント通知(例:エラーコード、警告コード、オーディオ・ビデオの状態パラメータなど)private TRTCCloudListener trtcSdkListener = new TRTCCloudListener() {@Overridepublic void onError(int errCode, String errMsg, Bundle extraInfo) {Log.d(TAG, errCode + errMsg);}@Overridepublic void onWarning(int warningCode, String warningMsg, Bundle extraInfo) {Log.d(TAG, warningCode + warningMsg);}};// イベントリスナーを削除mTRTCCloud.setListener(null);// RTC Engine SDK インスタンスの破棄(シングルトンパターン)TRTCCloud.destroySharedInstance();
// ログイン:userIDはカスタマイズ可能、userSigはステップ1を参照して取得します。V2TIMManager.getInstance().login(userID, userSig, new V2TIMCallback() {@Overridepublic void onSuccess() {Log.i("imsdk", "success");}@Overridepublic void onError(int code, String desc) {// 以下のエラーコードが返された場合、UserSigの使用期限が切れている。新しく発行されたUserSigを使用して再ログインします。// 1. ERR_USER_SIG_EXPIRED(6206)// 2. ERR_SVR_ACCOUNT_USERSIG_EXPIRED(70001)// 注意:他のエラーコードの場合は、ここでログインインターフェースを呼び出さないでください。Chat SDK のログインが無限ループになるのを避けるためです。Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);}});
// ログアウトV2TIMManager.getInstance().logout(new V2TIMCallback() {@Overridepublic void onSuccess() {Log.i("imsdk", "success");}@Overridepublic void onError(int code, String desc) {Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);}});
V2TIMManager.getInstance().createGroup(V2TIMManager.GROUP_TYPE_AVCHATROOM, groupID, groupName, new V2TIMValueCallback<String>() {@Overridepublic void onSuccess(String s) {// グループの作成に成功}@Overridepublic void onError(int code, String desc) {// グループの作成に失敗}});// グループ作成通知をリスニングV2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupCreated(String groupID) {// グループ作成コールバック、groupIDは新しく作成されたグループのID}});
GROUP_TYPE_AVCHATROOMを選択する必要があります。V2TIMManager.getInstance().joinGroup(groupID, message, new V2TIMCallback() {@Overridepublic void onSuccess() {// グループへの参加に成功}@Overridepublic void onError(int code, String desc) {// グループへの参加に失敗}});// グループ参加イベントをリスニングV2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onMemberEnter(String groupID, List<V2TIMGroupMemberInfo> memberList) {// 誰かがグループに参加しました。}});
private void enterRoom(String roomId, String userId) {TRTCCloudDef.TRTCParams params = new TRTCCloudDef.TRTCParams();// 文字列のルーム番号を例にしています。Chatのグループ番号と一致させることをお勧めします。params.strRoomId = roomId;params.userId = userId;// 業務バックエンドから取得したUserSigparams.userSig = getUserSig(userId);// 自分のSDKAppIDに置き換えるparams.sdkAppId = SDKAppID;// ボイスチャットインタラクションシナリオでの入室には、指定されたユーザーロールが必要です。params.role = TRTCCloudDef.TRTCRoleAudience;// ボイスチャットのインタラクションでの入室シナリオを例にmTRTCCloud.enterRoom(params, TRTCCloudDef.TRTC_APP_SCENE_VOICE_CHATROOM);}// 入室結果イベントコールバック@Overridepublic void onEnterRoom(long result) {if (result > 0) {// resultは入室にかかった時間(ミリ秒)Log.d(TAG, "Enter room succeed");} else {// result入室失敗のエラーコードLog.d(TAG, "Enter room failed");}}
roomIdと文字列型のstrRoomIdに分かれており、2種類のルームは相互接続されません。ルーム番号のタイプを統一することをお勧めします。TRTC_APP_SCENE_VOICE_CHATROOMがお勧めです。V2TIMManager.getInstance().quitGroup(groupID, new V2TIMCallback() {@Overridepublic void onSuccess() {// グループからの退出に成功}@Overridepublic void onError(int code, String desc) {// グループからの退出に失敗}});V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onMemberLeave(String groupID, V2TIMGroupMemberInfo member) {// グループメンバー退出コールバック}});
dismissGroupを使用してグループを解散することのみが可能です。private void exitRoom() {mTRTCCloud.stopLocalAudio();mTRTCCloud.exitRoom();}// 退室イベントコールバック@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "exitRoomアクティブコールでルーム退出します");} else if (reason == 1) {Log.d(TAG, "現在のルームからサーバーによってキックされました");} else if (reason == 2) {Log.d(TAG, "現在のルームは解散されました");}}
onExitRoomコールバック通知をスローして知らせます。enterRoomを呼び出す場合や他のオーディオ・ビデオSDKに切り替える場合は、onExitRoomのコールバックが返ってくるまで関連操作を行わないでください。そうしないと、カメラやマイクが強制的に使用されるなど、さまざまな異常が発生する可能性があります。V2TIMManager.getInstance().dismissGroup(groupID, new V2TIMCallback() {@Overridepublic void onSuccess() {// グループ解散に成功}@Overridepublic void onError(int code, String desc) {// グループ解散に失敗}});V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupDismissed(String groupID, V2TIMGroupMemberInfo opUser) {// グループ解散コールバック}});
DismissRoom(数字ルームIDと文字列ルームIDを区別)を提供しています。このインターフェースを呼び出すことで、ルーム内の全ユーザーを退室させ、ルームを解散することができます。exitRoom インターフェースを通じて、ルーム内の全ての配信者と視聴者の退室を完了させます。RTC Engineのルームライフサイクルルールに従い、ルームは自動的に解散されます。詳細はルーム退室をご参照ください。public class SeatInfo implements Serializable {public static final transient int STATUS_UNUSED = 0;public static final transient int STATUS_USED = 1;public static final transient int STATUS_LOCKED = 2;// 座席状態、3つの状態に対応public int status;// 座席はミュート状態かpublic boolean mute;// 座席が埋まっている場合、ユーザー情報を保存public String userId;@Overridepublic String toString() {return "TXSeatInfo{"+ "status=" + status+ ", mute=" + mute+ ", user='" + userId + '\\''+ '}';}}
// 聞き手がマイクオンの申請を送信、userIdはアンカーのID、dataは識別シグナルを伝えるためのjsonprivate String sendInvitation(String userId, String data) {return V2TIMManager.getSignalingManager().invite(userId, data, true, null, 0, new V2TIMCallback() {@Overridepublic void onError(int i, String s) {Log.e(TAG, "sendInvitation error " + i);}@Overridepublic void onSuccess() {Log.i(TAG, "sendInvitation success ");}});}// ホストがマイクオンの申請を受信、inviteIDはこの申請のID、inviterは申請者のIDV2TIMManager.getSignalingManager().addSignalingListener(new V2TIMSignalingListener() {@Overridepublic void onReceiveNewInvitation(String inviteID, String inviter,String groupId, List<String> inviteeList, String data) {Log.i(TAG, "received invitation: " + inviteID + " from " + inviter);}});
// マイクオンの申請を承認private void acceptInvitation(String inviteID, String data) {V2TIMManager.getSignalingManager().accept(inviteID, data, new V2TIMCallback() {@Overridepublic void onError(int i, String s) {Log.e(TAG, "acceptInvitation error " + i);}@Overridepublic void onSuccess() {Log.i(TAG, "acceptInvitation success ");}});}// マイクオンの申請を拒否private void rejectInvitation(String inviteID, String data) {V2TIMManager.getSignalingManager().reject(inviteID, data, new V2TIMCallback() {@Overridepublic void onError(int i, String s) {Log.e(TAG, "rejectInvitation error " + i);}@Overridepublic void onSuccess() {Log.i(TAG, "rejectInvitation success ");}});}
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// マイクオン申請承認のコールバックV2TIMManager.getSignalingManager().addSignalingListener(new V2TIMSignalingListener() {@Overridepublic void onInviteeAccepted(String inviteID, String invitee, String data) {Log.i(TAG, "received accept invitation: " + inviteID + " from " + invitee);takeSeat(seatIndex);}});// 聞き手がマイクオンprivate void takeSeat(int seatIndex) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = SeatInfo.STATUS_USED;seatInfo.mute = localInfo.mute;seatInfo.userId = mUserId;// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、マイクオン失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、TRTCのロールを切り替えてプッシュを開始mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);}});}
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// アンカー側がこのインターフェースを呼び出し、グループ属性に保存されたマイク情報を変更private void pickSeat(String userId, int seatIndex) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = SeatInfo.STATUS_USED;seatInfo.mute = localInfo.mute;seatInfo.userId = userId;// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、視聴者のマイクオン招待に失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、onGroupAttributeChangedコールバックをトリガー}});}// 聞き手側がグループ属性の変更コールバックを受け取り、自身の情報と一致した後にプッシュを開始V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupAttributeChanged(String groupID, Map<String, String> groupAttributeMap) {// 最後にローカルに保存された全マイク情報リストfinal List<SeatInfo> oldSeatInfoList = mSeatInfoList;// groupAttributeMapから解析された全てのマイク情報リストfinal List<SeatInfo> newSeatInfoList = getSeatListFromAttr(groupAttributeMap, seatSize);// 全マイク情報リストをトラバースし、新旧のマイク情報を比較for (int i = 0; i < seatSize; i++) {SeatInfo oldInfo = oldSeatInfoList.get(i);SeatInfo newInfo = newSeatInfoList.get(i);if (oldInfo.status != newInfo.status && newInfo.status == SeatInfo.STATUS_USED) {if (newInfo.userId.equals(mUserId)) {// 自身情報のマッチングに成功、TRTCのロールに切り替えてプッシュを開始mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor);mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);} else {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}});
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;private void leaveSeat(int seatIndex) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = SeatInfo.STATUS_UNUSED;seatInfo.mute = localInfo.mute;seatInfo.userId = "";// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、マイクオフに失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、TRTCのロールに切り替えプッシュを停止mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);mTRTCCloud.stopLocalAudio();}});}
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// アンカー側がこのインターフェースを呼び出し、グループ属性に保存されたマイク情報を変更private void kickSeat(int seatIndex) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = SeatInfo.STATUS_UNUSED;seatInfo.mute = localInfo.mute;seatInfo.userId = "";// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、強制マイクオフ失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、onGroupAttributeChangedコールバックをトリガー}});}// マイクオンの聞き手側がグループ属性の変更コールバックを受信し、自身の情報とマッチした後にプッシュを停止V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupAttributeChanged(String groupID, Map<String, String> groupAttributeMap) {// 最後にローカルに保存された全マイク情報リストfinal List<SeatInfo> oldSeatInfoList = mSeatInfoList;// groupAttributeMapから解析された全てのマイク情報リストfinal List<SeatInfo> newSeatInfoList = getSeatListFromAttr(groupAttributeMap, seatSize);// 全マイク情報リストをトラバースし、新旧のマイク情報を比較for (int i = 0; i < seatSize; i++) {SeatInfo oldInfo = oldSeatInfoList.get(i);SeatInfo newInfo = newSeatInfoList.get(i);if (oldInfo.status != newInfo.status && newInfo.status == SeatInfo.STATUS_UNUSED) {if (oldInfo.userId.equals(mUserId)) {// 自身情報のマッチングに成功、TRTCのロールに切り替えプッシュを停止mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAudience);mTRTCCloud.stopLocalAudio();} else {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}});
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// アンカー側がこのインターフェースを呼び出し、グループ属性に保存されたマイク情報を変更private void muteSeat(int seatIndex, boolean mute) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = localInfo.status;seatInfo.mute = mute;seatInfo.userId = localInfo.userId;// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、マイクミュートに失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、onGroupAttributeChangedコールバックをトリガー}});}// マイクオンの聞き手側がグループ属性の変更コールバックを受信し、自身の情報とマッチした後にプッシュを一時停止/再開V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupAttributeChanged(String groupID, Map<String, String> groupAttributeMap) {// 最後にローカルに保存された全マイク情報リストfinal List<SeatInfo> oldSeatInfoList = mSeatInfoList;// groupAttributeMapから解析された全てのマイク情報リストfinal List<SeatInfo> newSeatInfoList = getSeatListFromAttr(groupAttributeMap, seatSize);// 全マイク情報リストをトラバースし、新旧のマイク情報を比較for (int i = 0; i < seatSize; i++) {SeatInfo oldInfo = oldSeatInfoList.get(i);SeatInfo newInfo = newSeatInfoList.get(i);if (oldInfo.mute != newInfo.mute) {if (oldInfo.userId.equals(mUserId)) {// 自身情報のマッチングに成功し、ローカルプッシュの一時停止/再開mTRTCCloud.muteLocalAudio(newInfo.mute);} else {// ローカルマイクリストを更新し、ローカルマイクのビューをレンダリング}}}}});
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// アンカー側がこのインターフェースを呼び出し、グループ属性に保存されたマイク情報を変更private void lockSeat(int seatIndex, boolean isLock) {// マイク情報のインスタンスを作成し、変更後のマイク情報を保存SeatInfo localInfo = mSeatInfoList.get(seatIndex);SeatInfo seatInfo = new SeatInfo();seatInfo.status = isLock ? SeatInfo.STATUS_LOCKED : SeatInfo.STATUS_UNUSED;seatInfo.mute = localInfo.mute;seatInfo.userId = "";// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();String json = gson.toJson(seatInfo, SeatInfo.class);HashMap<String, String> map = new HashMap<>();map.put("seat" + seatIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、マイクロックに失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、onGroupAttributeChangedコールバックをトリガー}});}// 聞き手側がグループ属性の変更コールバックを受信し、対応するマイクのビューを更新V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupAttributeChanged(String groupID, Map<String, String> groupAttributeMap) {// 最後にローカルに保存された全マイク情報リストfinal List<SeatInfo> oldSeatInfoList = mSeatInfoList;// groupAttributeMapから解析された全てのマイク情報リストfinal List<SeatInfo> newSeatInfoList = getSeatListFromAttr(groupAttributeMap, seatSize);// 全マイク情報リストをトラバースし、新旧のマイク情報を比較for (int i = 0; i < seatSize; i++) {SeatInfo oldInfo = oldSeatInfoList.get(i);SeatInfo newInfo = newSeatInfoList.get(i);if (oldInfo.status == SeatInfo.STATUS_LOCKED && newInfo.status == SeatInfo.STATUS_UNUSED) {// マイクのロックを解除} else if (oldInfo.status != newInfo.status && newInfo.status == SeatInfo.STATUS_LOCKED) {// マイクをロック}}}});
// ローカルに保存された全部のマイク情報リストprivate List<SeatInfo> mSeatInfoList;// マイクオンアンカーがこのインターフェースを呼び出して、グループ属性に保存されたマイク情報を変更しますprivate void moveSeat(int dstIndex) {// userIdからソースマイクポジションの番号を取得int srcIndex = -1;for (int i = 0; i < mSeatInfoList.size(); i++) {SeatInfo seatInfo = mSeatInfoList.get(i);if (seatInfo != null && mUserId.equals(seatInfo.userId)) {srcIndex = i;break;}}// マイクポジション番号に基づいて対応するマイク情報を取得SeatInfo srcSeatInfo = mSeatInfoList.get(srcIndex);SeatInfo dstSeatInfo = mSeatInfoList.get(dstIndex);// マイク情報インスタンスを作成し、変更後のソースマイク情報を保存SeatInfo srcChangeInfo = new SeatInfo();srcChangeInfo.status = SeatInfo.STATUS_UNUSED;srcChangeInfo.mute = srcSeatInfo.mute;srcChangeInfo.userId = "";// マイク情報インスタンスを作成し、変更後のターゲットマイク情報を保存SeatInfo dstChangeInfo = new SeatInfo();dstChangeInfo.status = SeatInfo.STATUS_USED;dstChangeInfo.mute = dstSeatInfo.mute;dstChangeInfo.userId = mUserId;// マイク情報オブジェクトをJSON形式にシリアライズGson gson = new Gson();HashMap<String, String> map = new HashMap<>();String json = gson.toJson(srcChangeInfo, SeatInfo.class);map.put("seat" + srcIndex, json);json = gson.toJson(dstChangeInfo, SeatInfo.class);map.put("seat" + dstIndex, json);// グループ属性を設定し、そのグループ属性が既に存在する場合はそのvalueの値を更新、存在しない場合はその属性を追加V2TIMManager.getGroupManager().setGroupAttributes(groupId, map, new V2TIMCallback() {@Overridepublic void onError(int code, String message) {// グループ属性の変更に失敗、マイクポジション移動に失敗}@Overridepublic void onSuccess() {// グループ属性の変更に成功、マイクポジション移動に成功}});}
muteRemoteAudio(userId, mute)を追加で呼び出してリモートユーザーのオーディオストリームを購読および再生する必要があります。// 自動購読モード(デフォルト)mTRTCCloud.setDefaultStreamRecvMode(true, true);// 手動購読モード(カスタム)mTRTCCloud.setDefaultStreamRecvMode(false, false);
setDefaultStreamRecvModeは、入室enterRoomする前に呼び出す必要があります。// ローカルオーディオのキャプチャーとパブリッシュを有効にします。mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT)// ローカルオーディオのキャプチャーとパブリッシュを停止するmTRTCCloud.stopLocalAudio();
startLocalAudioはマイクの使用権限を申請し、stopLocalAudioはマイクの使用権限をリリースします。// ローカルオーディオストリームのパブリッシュを一時停止(マイクオフ)mTRTCCloud.muteLocalAudio(true);// ローカルオーディオストリームのパブリッシュを再開(マイクオン)mTRTCCloud.muteLocalAudio(false);// 特定のリモートユーザーのオーディオストリームの購読と再生を一時停止mTRTCCloud.muteRemoteAudio(userId, true);// 特定のリモートユーザーのオーディオストリームの購読と再生を再開mTRTCCloud.muteRemoteAudio(userId, false);// すべてのリモートユーザーのオーディオストリームの購読と再生を一時停止mTRTCCloud.muteAllRemoteAudio(true);// すべてのリモートユーザーのオーディオストリームの購読と再生を再開mTRTCCloud.muteAllRemoteAudio(false);
muteLocalAudioはソフトウェアレベルでデータフローを一時停止または再開するだけでよいため、効率が高くスムーズで、頻繁にマイクのオンオフが必要なシナリオに適しています。// ローカルオーディオのキャプチャーとパブリッシュ時の音質設定mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);// オーディオプッシュ中に音質を動的に設定mTRTCCloud.setAudioQuality(TRTCCloudDef.TRTC_AUDIO_QUALITY_DEFAULT);
// 音量タイプの設定mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeAuto);
// オーディオルーティングの設定mTRTCCloud.setAudioRoute(TRTCCloudDef.TRTC_AUDIO_ROUTE_SPEAKER);
// パブリックチャットに弾幕メッセージを送信V2TIMManager.getInstance().sendGroupTextMessage(text, groupID, V2TIMMessage.V2TIM_PRIORITY_NORMAL, new V2TIMValueCallback<V2TIMMessage>() {@Overridepublic void onError(int i, String s) {// 弾幕メッセージの送信に失敗}@Overridepublic void onSuccess(V2TIMMessage v2TIMMessage) {// 弾幕メッセージの送信に成功}});// パブリックチャットの弾幕メッセージを受信V2TIMManager.getInstance().addSimpleMsgListener(new V2TIMSimpleMsgListener() {@Overridepublic void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {Log.i(TAG, sender.getNickName + ": " + text);}});
// 音量コールバックを有効にすることをお勧めします。入室に成功した後すぐに開始してください。// interval: コールバック間(ms); enable_vad: ボイス検出の有無mTRTCCloud.enableAudioVolumeEvaluation(int interval, boolean enable_vad);private class TRTCCloudImplListener extends TRTCCloudListener {public void onUserVoiceVolume(ArrayList<TRTCCloudDef.TRTCVolumeInfo> userVolumes, int totalVolume) {super.onUserVoiceVolume(userVolumes, totalVolume);// userVolumesはすべての話しているユーザーの音量で、ローカルユーザーとリモートプッシュユーザーを含みます。// totalVolumeはリモートのプッシュユーザーの最大音量値のフィードバックです。...// 音量の大きさに応じてUI上で適切な表示を行います。...}}
userVolumesは配列であり、配列内の各要素において、userIdが空の場合はローカルのマイクからキャプチャーした音量の大きさを表し、が空でない場合はリモートユーザーの音量の大きさを表します。// BGM、効果音、およびボイスエフェクトの設定を行うための管理クラスを取得TXAudioEffectManager mTXAudioEffectManager = mTRTCCloud.getAudioEffectManager();TXAudioEffectManager.AudioMusicParam param = new TXAudioEffectManager.AudioMusicParam(musicID, musicPath);// 音楽をリモートにパブリッシュするか(そうでなければローカルのみで再生)param.publish = true;// 効果音ファイルかparam.isShortFile = false;// BGMの再生を開始mTXAudioEffectManager.startPlayMusic(param);// BGMの再生を停止mTXAudioEffectManager.stopPlayMusic(musicID);// BGMの再生を一時停止mTXAudioEffectManager.pausePlayMusic(musicID);// BGMの再生を再開mTXAudioEffectManager.resumePlayMusic(musicID);
musicPath にローカルの絶対パスまたは URL アドレスを渡します。MP3/AAC/M4A/WAV 形式をサポートします。// BGMのローカル再生ボリュームの設定mTXAudioEffectManager.setMusicPlayoutVolume(musicID, volume);// BGMのリモート再生ボリュームの設定mTXAudioEffectManager.setMusicPublishVolume(musicID, volume);// すべてのBGMのローカルとリモート音量の設定mTXAudioEffectManager.setAllMusicVolume(volume);// ボーカルのキャプチャーボリュームの設定mTXAudioEffectManager.setVoiceCaptureVolume(volume);
muteLocalAudio(true)をsetVoiceCaptureVolume(0)で置き換えてください。mTXAudioEffectManager.setMusicObserver(mCurPlayMusicId, new TXAudioEffectManager.TXMusicPlayObserver() {@Override// BGMの再生を開始public void onStart(int id, int errCode) {// -4001: パスのオープンに失敗// -4002: デコード失敗// -4003: URLアドレス無効// -4004: 再生中if (errCode < 0) {// 再生失敗後、再開する前に現在の再生を停止する必要があります。mTXAudioEffectManager.stopPlayMusic(id);}}@Override// BGMの再生の進捗状況public void onPlayProgress(int id, long curPtsMs, long durationMs) {// curPtsMS現在の再生時間(ミリ秒)// durationMs現在の音楽の総時間(ミリ秒)}@Override// BGMの再生が終了public void onComplete(int id, int errCode) {// 回線品質低下によって引き起こされる再生の失敗もこのコールバックをスロー、この時errCode < 0// 途中で一時停止または停止してもonCompleteコールバックはトリガーされません。}});
setMusicObserver(musicId, null)を実行してObserverを完全にリリースできます。AudioMusicParamのloopCountパラメータを使用して、ループ再生回数を設定します。private void startPlayMusic(int id, String path, int loopCount) {TXAudioEffectManager.AudioMusicParam param = new TXAudioEffectManager.AudioMusicParam(id, path);// 音楽をリモートにパブリッシュするかparam.publish = true;// 効果音ファイルかparam.isShortFile = true;// ループ再生回数を設定、負数は無限ループparam.loopCount = loopCount < 0 ? Integer.MAX_VALUE : loopCount;mTRTCCloud.getAudioEffectManager().startPlayMusic(param);}
onCompleteコールバックはトリガーされません。設定されたループ回数がすべて完了した後にのみ、そのコールバックがトリガーされます。onCompleteを利用してループ再生を実装します。通常はリストループまたは単曲ループに使用されます。// ループ再生するかどうかを示すメンバー変数private boolean loopPlay;private void startPlayMusic(int id, String path) {TXAudioEffectManager.AudioMusicParam param = new TXAudioEffectManager.AudioMusicParam(id, path);mTXAudioEffectManager.setMusicObserver(id, new MusicPlayObserver(id, path));mTXAudioEffectManager.startPlayMusic(param);}private class MusicPlayObserver implements TXAudioEffectManager.TXMusicPlayObserver {private final int mId;private final String mPath;public MusicPlayObserver(int id, String path) {mId = id;mPath = path;}@Overridepublic void onStart(int i, int i1) {}@Overridepublic void onPlayProgress(int i, long l, long l1) {}@Overridepublic void onComplete(int i, int i1) {mTXAudioEffectManager.stopPlayMusic(i);if (i1 >= 0 && loopPlay) {// ここでループリストの音楽ID、Pathに置き換えることができます。startPlayMusic(mId, mPath);}}}
private void startPublishMediaToRoom(String roomId, String userId) {// TRTCPublishTargetオブジェクトを作成TRTCCloudDef.TRTCPublishTarget target = new TRTCCloudDef.TRTCPublishTarget();// ミキシング後にルームにプッシュバックtarget.mode = TRTCCloudDef.TRTC_PublishMixStream_ToRoom;target.mixStreamIdentity.strRoomId = roomId;// ミキシングロボットのuseridは、ルームの他のユーザーのuseridと重複してはいけません。target.mixStreamIdentity.userId = userId + MIX_ROBOT;// トランスコード後のオーディオストリームのエンコードパラメータを設定する(カスタマイズ可能)TRTCCloudDef.TRTCStreamEncoderParam trtcStreamEncoderParam = new TRTCCloudDef.TRTCStreamEncoderParam();trtcStreamEncoderParam.audioEncodedChannelNum = 2;trtcStreamEncoderParam.audioEncodedKbps = 64;trtcStreamEncoderParam.audioEncodedCodecType = 2;trtcStreamEncoderParam.audioEncodedSampleRate = 48000;// トランスコードされたビデオストリームのエンコードパラメータを設定(オーディオストリームミックスの場合は無視しても良い)trtcStreamEncoderParam.videoEncodedFPS = 15;trtcStreamEncoderParam.videoEncodedGOP = 3;trtcStreamEncoderParam.videoEncodedKbps = 30;trtcStreamEncoderParam.videoEncodedWidth = 64;trtcStreamEncoderParam.videoEncodedHeight = 64;// オーディオストリームミックスのパラメータを設定TRTCCloudDef.TRTCStreamMixingConfig trtcStreamMixingConfig = new TRTCCloudDef.TRTCStreamMixingConfig();// デフォルトでは空欄のままで大丈夫です。これは、ルーム内のすべてのオーディオがミキシングされることを意味します。trtcStreamMixingConfig.audioMixUserList = null;// ビデオストリームミックステンプレートの配置(オーディオストリームミックスの場合は無視しても良い)TRTCCloudDef.TRTCVideoLayout videoLayout = new TRTCCloudDef.TRTCVideoLayout();trtcStreamMixingConfig.videoLayoutList.add(videoLayout);// オーディオ・ビデオストリームプッシュバックを開始mTRTCCloud.startPublishMediaStream(target, trtcStreamEncoderParam, trtcStreamMixingConfig);}
private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onStartPublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {// taskId: リクエストが成功した場合、TRTCバックエンドはコールバックでこのタスクのtaskIdを提供し、その後、そのtaskIdをupdatePublishMediaStreamとstopPublishMediaStreamと組み合わせて更新および停止することができます。// code: コールバック結果、0は成功を意味し、その他の値は失敗を意味します。}@Overridepublic void onUpdatePublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {// メディアストリームのパブリッシュインターフェース(updatePublishMediaStream)を呼び出す際にに渡したtaskIdは、このコールバックを通じて再度返され、どの更新リクエストに属するかを識別するために使用されます。// code: コールバック結果、0は成功を意味し、その他の値は失敗を意味します。}@Overridepublic void onStopPublishMediaStream(String taskId, int code, String message, Bundle extraInfo) {// メディアストリームのパブリッシュ停止(stopPublishMediaStream)を呼び出す際にに渡したtaskIdは、このコールバックを通じて再度返され、どの停止リクエストに属するかを識別するために使用されます。// code: コールバック結果、0は成功を意味し、その他の値は失敗を意味します。}}
startPublishMediaStream で起動したメディアストリームを更新します。// taskId: onStartPublishMediaStreamでコールバックされたタスクID// target: 例えば、パブリッシュしたCDN URLの追加、削除// params: メディアストリームのエンコード出力パラメータを一貫して保持することがお勧めです。これにより、再生側での中断を避けることができます。// config: ストリームミックストランスコーディングに参加するユーザーリストを更新。例えば、クロスルームPKなど。mTRTCCloud.updatePublishMediaStream(taskId, target, trtcStreamEncoderParam, trtcStreamMixingConfig);
startPublishMediaStream で起動したメディアストリームを停止します。// taskId: onStartPublishMediaStreamでコールバックされたタスクIDmTRTCCloud.stopPublishMediaStream(taskId);
startPublishMediaStreamで開始されたそのユーザーのすべてのメディアストリームが停止します。1つのメディアストリームのみを開始した場合や、自分が開始したすべてのメディアストリームを停止したい場合は、この方法をお勧めします。onNetworkQualityをリスニングすることができます。このコールバックは2秒ごとに一度発生します。private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onNetworkQuality(TRTCCloudDef.TRTCQuality localQuality,ArrayList<TRTCCloudDef.TRTCQuality> remoteQuality) {// localQuality userIdは空、ローカルユーザーのネットワーク品質評価結果を表します// remoteQualityは、リモートユーザーのネットワーク品質評価結果を表しており、その結果はリモートとローカルの両方の影響を受けます。switch (localQuality.quality) {case TRTCCloudDef.TRTC_QUALITY_Excellent:Log.i(TAG, "現在のネットワークは非常に良い");break;case TRTCCloudDef.TRTC_QUALITY_Good:Log.i(TAG, "現在のネットワークは比較的良い");break;case TRTCCloudDef.TRTC_QUALITY_Poor:Log.i(TAG, "現在のネットワークは普通");break;case TRTCCloudDef.TRTC_QUALITY_Bad:Log.i(TAG, "現在のネットワークが不安定");break;case TRTCCloudDef.TRTC_QUALITY_Vbad:Log.i(TAG, "現在のネットワークが非常に悪い");break;case TRTCCloudDef.TRTC_QUALITY_Down:Log.i(TAG, "現在のネットワークはTRTC最低要件を満たしていない");break;default:Log.i(TAG, "未定義");break;}}}
TRTCCloudDef.TRTCParams mTRTCParams = new TRTCCloudDef.TRTCParams();mTRTCParams.sdkAppId = SDKAPPID;mTRTCParams.userId = mUserId;mTRTCParams.strRoomId = mRoomId;// 業務バックエンドから取得したUserSigmTRTCParams.userSig = getUserSig();// 業務バックエンドから取得したPrivateMapKeymTRTCParams.privateMapKey = getPrivateMapKey();mTRTCParams.role = TRTCCloudDef.TRTCRoleAudience;mTRTCCloud.enterRoom(mTRTCParams, TRTCCloudDef.TRTC_APP_SCENE_VOICE_CHATROOM);
// 業務バックエンドから最新のPrivateMapKeyを取得し、ロール切り替えインターフェースに渡します。mTRTCCloud.switchRole(TRTCCloudDef.TRTCRoleAnchor, getPrivateMapKey());
列挙値 | 取得値 | 説明 |
ERR_TRTC_INVALID_USER_SIG | -3320 | 入室パラメータUserSigが正しくありません。 TRTCParams.userSigが空であるかどうかを確認してください。 |
ERR_TRTC_USER_SIG_CHECK_FAILED | -100018 | UserSig検証失敗、パラメータ TRTCParams.userSigが正しく入力されているか、または期限切れでないかを確認してください。 |
列挙値 | 取得値 | 説明 |
ERR_TRTC_CONNECT_SERVER_TIMEOUT | -3308 | 入室リクエストがタイムアウトしました。ネットワークが切断されているか、VPNが使用されているかを確認してください。また、4Gに切り替えてテストすることもできます。 |
ERR_TRTC_INVALID_SDK_APPID | -3317 | 入室パラメータsdkAppIdエラー。 TRTCParams.sdkAppIdが空であるかどうか確認してください。 |
ERR_TRTC_INVALID_ROOM_ID | -3318 | 入室パラメータroomIdエラー。 TRTCParams.roomIdまたはTRTCParams.strRoomIdが空であるかどうか確認してください。roomIdとstrRoomIdは混在できません。 |
ERR_TRTC_INVALID_USER_ID | -3319 | 入室パラメータuserIdが正しくありません。 TRTCParams.userIdが空であるかどうかを確認してください。 |
ERR_TRTC_ENTER_ROOM_REFUSED | -3340 | 入室リクエストが拒否されました。 enterRoomで同じIdのルームに連続して入室しようとしていないか確認してください。 |
列挙値 | 取得値 | 説明 |
ERR_MIC_START_FAIL | -1302 | マイクの起動に失敗しました。例えば、WindowsまたはMacデバイスで、マイクの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。 |
ERR_SPEAKER_START_FAIL | -1321 | スピーカーの起動に失敗しました。例えば、WindowsやMacのデバイスで、スピーカーの設定プログラム(ドライバー)に異常があります。デバイスを無効にしてから再度有効にするか、マシンを再起動するか、設定プログラムを更新してください。 |
ERR_MIC_OCCUPY | -1319 | マイクが使用中です。たとえば、モバイルデバイスが通話中の場合、マイクを開くと失敗します。 |
onConnectionLostコールバック受信後、ローカルのマイクポジションUIにネットワーク切断の警告を表示し、ユーザーに通知します。同時に、ローカルでタイマーを起動し、設定された時間閾値を超えてもonConnectionRecoveryコールバックが受信されない場合、つまりネットワークが継続して切断状態にある場合は、ローカルでマイクオフにし、退室プロセスを開始し、同時にポップアップウィンドウでユーザーにルームからの退出とページの破棄を通知します。ネットワーク切断が90秒(デフォルト)を超えると、タイムアウトによる退房がトリガーされ、RTC Engine サーバーは該当ユーザーをルームから退出させます。もし該当ユーザーが配信者ロールの場合、ルーム内の他のユーザーは onRemoteUserLeaveRoom コールバックを受信します。private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onConnectionLost() {// SDKクラウドとの接続が切断されました。}@Overridepublic void onTryToReconnect() {// SDKクラウドに再接続しています。}@Overridepublic void onConnectionRecovery() {// SDKクラウドとの接続が復旧されました。}}
// アンカーがマイクオン聞き手ユーザーの状態を購読V2TIMManager.getInstance().subscribeUserStatus(userList, new V2TIMCallback() {@Overridepublic void onSuccess() {// ユーザーステータスの購読に成功}@Overridepublic void onError(int code, String message) {// ユーザーステータスの購読に失敗}});// アンカーがマイクオフの聞き手ユーザーのステータスの購読をキャンセルV2TIMManager.getInstance().unsubscribeUserStatus(userList, new V2TIMCallback() {@Overridepublic void onSuccess() {// ユーザーステータスの購読解除に成功}@Overridepublic void onError(int code, String message) {// ユーザーステータスの購読解除に失敗}});// ユーザーステータス変更通知と処理V2TIMManager.getInstance().addIMSDKListener(new V2TIMSDKListener() {@Overridepublic void onUserStatusChanged(List<V2TIMUserStatus> userStatusList) {for (V2TIMUserStatus userStatus : userStatusList) {final String userId = userStatus.getUserID();int status = userStatus.getStatusType();if (status == V2TIMUserStatus.V2TIM_USER_STATUS_OFFLINE) {// オフライン状態での強制マイクオフkickSeat(getSeatIndexFromUserId(userId));}}}});

subscribeUserStatus を呼び出すとエラーが報告されます。https://trtc.tencentcloudapi.com/?Action=RemoveUser&SdkAppId=1400000001&RoomId=1234&UserIds.0=test1&UserIds.1=test2&<公共リクエストパラメータ>
onExitRoom()コールバックを受け取り、reasonの値は1になります。この時、このコールバック内でマイクオフ、Chat グループ退出などの操作を処理できます。// TRTCルーム退出イベントコールバック@Overridepublic void onExitRoom(int reason) {if (reason == 0) {Log.d(TAG, "exitRoomアクティブコールでルーム退出します");} else {// reason 1: 現在のルームからサーバーによってキックされました。// reason 2: 現在のルームは解散されました。Log.d(TAG, "現在のルームからサーバーによってキックされたか、ルームが解散ました");// マイクオフleaveSeat(seatIndex);// IMグループから退出quitGroup(groupID, new V2TIMCallback() {});}}
https://xxxxxx/v4/group_open_http_svc/destroy_group?sdkappid=88888888&identifier=admin&usersig=xxx&random=99999999&contenttype=json
onGroupDismissed()コールバックを受け取ります。この時、そのコールバック内でTRTCルーム退出などの処理ができます。// グループ解散コールバックV2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {@Overridepublic void onGroupDismissed(String groupID, V2TIMGroupMemberInfo opUser) {// TRTCルームから退出mTRTCCloud.stopLocalAudio();mTRTCCloud.exitRoom();}});
exitRoom() を呼び出して退房を完了すると、RTC Engine ルームは自動的に解散します。もちろん、サーバー側インターフェース DismissRoom(整数型ルーム番号)または DismissRoomByStrRoomId(文字列型ルーム番号)を呼び出して RTC Engine ルームを強制的に解散することもできます。
V2TIMMessageListGetOption option = new V2TIMMessageListGetOption();option.setGetType(V2TIMMessageListGetOption.V2TIM_GET_CLOUD_OLDER_MSG); // クラウドからより古いメッセージを取得option.setGetTimeBegin(1640966400); // 2022-01-01 00:00:00から開始option.setGetTimePeriod(1 * 24 * 60 * 60); // 丸一日のメッセージを取得option.setCount(Integer.MAX_VALUE); // 指定された時間範囲内のすべてのメッセージを返します。option.setGroupID(#you group id#); // グループチャットメッセージの取得V2TIMManager.getMessageManager().getHistoryMessageList(option, new V2TIMValueCallback<List<V2TIMMessage>>() {@Overridepublic void onSuccess(List<V2TIMMessage> v2TIMMessages) {Log.i("imsdk", "success");}@Overridepublic void onError(int code, String desc) {Log.i("imsdk", "failure, code:" + code + ", desc:" + desc);}});
onUserAudioAvailable(userId, true) コールバックに基づいて対応する配信者のミュート状態を解除します。private class TRTCCloudImplListener extends TRTCCloudListener {@Overridepublic void onUserAudioAvailable(String userId, boolean available) {if (available) {// 対応するアンカーのミュート状態を解除}}}
V2TIMManager.getGroupManager().getGroupAttributes(groupID, null, new V2TIMValueCallback<Map<String, String>>() {@Overridepublic void onError(int i, String s) {// グループ属性の取得に失敗}@Overridepublic void onSuccess(Map<String, String> attrMap) {// グループ属性の取得に成功、アンカーのミュート状態のkeyをmuteStatusと仮定String muteStatus = attrMap.get("muteStatus");// muteStatusを分析し、各マイクオンアンカーのミュート状態を取得}});
mTRTCCloud.setSystemVolumeType(TRTCCloudDef.TRTCSystemVolumeTypeVOIP);
BLUETOOTH権限を設定する必要があり、Andorid 12以上のシステムでは少なくともBLUETOOTH_CONNECT権限を設定し、コード中で動的な権限の申請が必要です。<!--通常権限:基本Bluetooth接続権限--><uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/><!--通常権限:Bluetooth管理、スキャン権限--><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /><!--実行時権限:Android 12 Bluetooth権限 Bluetoothデバイスを検索--><uses-permission android:name="android.permission.BLUETOOTH_SCAN" /><!--実行時権限:Android 12 Bluetooth権限 現在のデバイスが他のBluetoothデバイスに検出可能にする--><uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /><!--実行時権限:Android 12 Bluetooth権限 ペアリングされたBluetoothデバイスとの通信または現在の携帯電話のBluetoothオンオフ状態を取得--><uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
private List<String> permissionList = new ArrayList<>();protected void initPermission() {// Android SDKのバージョンを判断、Android 12以上かif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {// ニーズに応じて、動的な申請が必要な権限を追加permissionList.add(Manifest.permission.BLUETOOTH_SCAN);permissionList.add(Manifest.permission.BLUETOOTH_ADVERTISE);permissionList.add(Manifest.permission.BLUETOOTH_CONNECT);}if (permissionList.size() != 0) {// 動的な権限申請ActivityCompat.requestPermissions(this, permissionList.toArray(new String[0]), REQ_PERMISSION_CODE);}}
startPlayMusic を使用してバックグラウンドミュージックを再生する場合、音楽リソースパスパラメータ path には、Android 開発における assets/raw など、アプリケーションリソースファイルを保存するディレクトリ下のファイルパスを渡すことはサポートされていません。これらのディレクトリ下のファイルは APK にパッケージ化され、インストール後は携帯電話のファイルシステムに解凍されないためです。現在サポートされているのは、ネットワークリソース URL、Android デバイスの外部ストレージ、及びアプリケーションのプライベートディレクトリ下のリソースファイルの絶対パスのみです。public static void copyAssetsToFile(Context context, String name) {// アプリケーション自体のディレクトリ内のfilesディレクトリString savePath = ContextCompat.getExternalFilesDirs(context, null)[0].getAbsolutePath();// アプリケーション自体のディレクトリ内のcacheディレクトリ// String savePath = getApplication().getExternalCacheDir().getAbsolutePath();// アプリケーションのプライベートストレージディレクトリ内のfilesディレクトリ// String savePath = getApplication().getFilesDir().getAbsolutePath();String filename = savePath + "/" + name;File dir = new File(savePath);// ディレクトリが存在しない場合、このディレクトリを作成if (!dir.exists()) {dir.mkdir();}try {if (!(new File(filename)).exists()) {InputStream is = context.getResources().getAssets().open(name);FileOutputStream fos = new FileOutputStream(filename);byte[] buffer = new byte[1024];int count = 0;while ((count = is.read(buffer)) > 0) {fos.write(buffer, 0, count);}fos.close();is.close();}} catch (Exception e) {e.printStackTrace();}}
/data/user/0/<package_name>/files/<file_name>/storage/emulated/0/Android/data/<package_name>/files/<file_name>/storage/emulated/0/Android/data/<package_name>/cache/file_name>android:requestLegacyExternalStorage="true"。この属性はtargetSdkVersionが29(Android 10)のアプリケーションでのみ有効で、より高いバージョンのtargetSdkVersionのアプリケーションでは、アプリのプライベートまたは外部ストレージパスの使用を引き続き推奨します。MANAGE_EXTERNAL_STORAGE権限の申請が必要です。<manifest ...><!-- This is the permission itself --><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /><application ...>...</application></manifest>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {if (!Environment.isExternalStorageManager()) {Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);Uri uri = Uri.fromParts("package", getPackageName(), null);intent.setData(uri);startActivity(intent);}} else {// For Android versions less than Android 11, you can use the old permissions modelActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);}
フィードバック