@trtc/calls-uikit-react 4.5.3-beta.1 → 4.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/Components/TUICallKit/TUICallKit.tsx +19 -0
- package/src/Components/components/SingleCall/MediaContainer/hooks/useGetLargeViewName.ts +9 -2
- package/src/Components/components/common/AutoPlayDialog/AutoPlayDialog.module.scss +33 -0
- package/src/Components/components/common/AutoPlayDialog/AutoPlayDialog.tsx +57 -0
- package/src/Components/components/common/AutoPlayDialog/index.ts +3 -0
- package/src/TUICallService/CallService/UIKitModal.ts +50 -12
- package/src/TUICallService/CallService/engineEventHandler.ts +4 -2
- package/src/TUICallService/CallService/index.ts +14 -14
- package/src/TUICallService/CallService/miniProgram.ts +4 -1
- package/src/TUICallService/UIKitModal/UIKitModal.ts +14 -5
- package/src/TUICallService/locales/en.ts +3 -0
- package/src/TUICallService/locales/ja_JP.ts +4 -2
- package/src/TUICallService/locales/zh-cn.ts +3 -0
- package/src/TUICallService/utils/env.ts +11 -1
- package/src/TUICallService/utils/permission.ts +294 -0
- package/src/TUICallService/utils/validate/avoidRepeatedCall.ts +5 -1
- package/src/index.ts +1 -1
- package/tuicall-uikit-react.es.js +2951 -2627
- package/tuicall-uikit-react.umd.js +4 -4
- package/types/Components/TUICallKit/TUICallKit.d.ts +2 -2
- package/types/Components/components/GroupCall/GroupCall.d.ts +1 -2
- package/types/Components/components/GroupCall/MediaContainer/AudioStream/AudioStream.d.ts +1 -2
- package/types/Components/components/GroupCall/MediaContainer/MediaContainer.d.ts +1 -2
- package/types/Components/components/GroupCall/MediaContainer/StreamLoading/StreamLoading.d.ts +1 -1
- package/types/Components/components/GroupCall/Waiting/Waiting.d.ts +1 -2
- package/types/Components/components/SingleCall/MediaContainer/AudioStream/AudioStream.d.ts +1 -2
- package/types/Components/components/SingleCall/MediaContainer/MediaContainer.d.ts +1 -2
- package/types/Components/components/SingleCall/SingleCall.d.ts +1 -1
- package/types/Components/components/SingleCall/Waiting/Waiting.d.ts +1 -2
- package/types/Components/components/base/Avatar/Avatar.d.ts +2 -2
- package/types/Components/components/base/Drag/Drag.d.ts +2 -2
- package/types/Components/components/base/Grid/Col/Col.d.ts +2 -2
- package/types/Components/components/base/Grid/Row/Row.d.ts +1 -1
- package/types/Components/components/base/GridLayout/GridLayout.d.ts +1 -2
- package/types/Components/components/base/GridLayout/GridPlusItem/GridPlusItem.d.ts +2 -2
- package/types/Components/components/base/Icon/Icon.d.ts +2 -2
- package/types/Components/components/base/Loading/Circle/Cilrcle.d.ts +1 -2
- package/types/Components/components/base/Loading/Dot/Dot.d.ts +1 -2
- package/types/Components/components/base/Loading/Loading.d.ts +2 -2
- package/types/Components/components/base/Message/Message.d.ts +2 -2
- package/types/Components/components/base/Message/MessageIcon/Error.d.ts +1 -1
- package/types/Components/components/base/Message/MessageIcon/Info.d.ts +1 -1
- package/types/Components/components/base/Message/MessageIcon/Success.d.ts +1 -1
- package/types/Components/components/base/Message/MessageIcon/Warning.d.ts +1 -1
- package/types/Components/components/base/Overlayer/Overlayer.d.ts +2 -2
- package/types/Components/components/base/Text/Text.d.ts +1 -2
- package/types/Components/components/base/Time/Time.d.ts +1 -2
- package/types/Components/components/base/ToggleWindow/ToggleWindow.d.ts +1 -1
- package/types/Components/components/base/ToggleWindow/ToggleWindowItem/ToggleWindowItem.d.ts +1 -2
- package/types/Components/components/common/AutoPlayDialog/AutoPlayDialog.d.ts +1 -0
- package/types/Components/components/common/AutoPlayDialog/index.d.ts +2 -0
- package/types/Components/components/common/ButtonPanel/ButtonPanel.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/ButtonPanelH5/ButtonPanelH5.d.ts +2 -2
- package/types/Components/components/common/ButtonPanel/ButtonPanelPC/ButtonPanelPC.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Accept/Accept.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/BackgroundBlur/BackgroundBlur.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Camera.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/FullScreen/FullScreen.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Hangup/Hangup.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Microphone.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Minimize/Minimize.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Reject/Reject.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/Speaker.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/SwitchAudioCall.d.ts +1 -2
- package/types/Components/components/common/ButtonPanel/button/SwitchCamera.d.ts +1 -2
- package/types/Components/components/common/CallMessage/CallMessage.d.ts +1 -1
- package/types/Components/components/common/CallMessage/CallMessageC2C/CallMessageC2C.d.ts +1 -2
- package/types/Components/components/common/CallMessage/CallMessageGroup/CallMessageGroup.d.ts +1 -2
- package/types/Components/components/common/DeviceSelector/DeviceSelector.d.ts +1 -2
- package/types/Components/components/common/FloatingWindow/FloatingWindow.d.ts +2 -2
- package/types/Components/components/common/FloatingWindow/FloatingWindowGroupCall/FloatingWindowGroupCall.d.ts +2 -2
- package/types/Components/components/common/FloatingWindow/FloatingWindowSingleCall/FloatingWindowSingleCall.d.ts +2 -2
- package/types/Components/components/common/MicrophoneVolumn/MicrophoneVolumn.d.ts +2 -2
- package/types/Components/components/common/OverlayStream/OverlayStream.d.ts +2 -2
- package/types/Components/components/common/Player/Player.d.ts +2 -2
- package/types/Components/components/common/Pusher/Pusher.d.ts +1 -1
- package/types/Components/components/common/StreamInfo/StreamInfo.d.ts +1 -2
- package/types/Components/components/common/StreamInfo/StreamInfoH5/StreamInfoH5.d.ts +1 -2
- package/types/Components/components/common/StreamInfo/StreamInfoPC/StreamInfoPC.d.ts +1 -2
- package/types/Components/components/common/Tip/Tip.d.ts +2 -2
- package/types/Components/components/common/TopBar/TopBar.d.ts +1 -2
- package/types/Components/components/common/TopBar/h5/TopBarH5.d.ts +1 -2
- package/types/Components/components/common/TopBar/pc/TopBarPC.d.ts +1 -2
- package/types/TUICallService/CallService/UIKitModal.d.ts +1 -1
- package/types/TUICallService/locales/en.d.ts +3 -0
- package/types/TUICallService/locales/ja_JP.d.ts +2 -0
- package/types/TUICallService/locales/zh-cn.d.ts +3 -0
- package/types/TUICallService/utils/env.d.ts +1 -0
- package/types/TUICallService/utils/permission.d.ts +88 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WeChat mini-program permission utility.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: This module is only referenced inside `// @if process.env.BUILD_TARGET='MINI'`
|
|
5
|
+
* conditional-compilation blocks, so it will be tree-shaken out of the web builds.
|
|
6
|
+
* `wx` global typings are not available in this package, therefore `// @ts-ignore`
|
|
7
|
+
* is used before each `wx.*` call, following the same convention as `miniProgram.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Distinguishes two levels of permission denial:
|
|
10
|
+
* 1. Mini-program level: the user has rejected the scope in this mini-program.
|
|
11
|
+
* Fix: call wx.openSetting to let the user toggle it.
|
|
12
|
+
* 2. System level: WeChat itself lacks the OS-level permission (Settings >
|
|
13
|
+
* Privacy > Microphone / Camera on iOS, App Permissions on Android).
|
|
14
|
+
* Fix: guide the user to the system settings page (cannot be opened
|
|
15
|
+
* programmatically).
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// ── Permission Scope Constants ──
|
|
19
|
+
export const PermissionScope = {
|
|
20
|
+
RECORD: 'scope.record',
|
|
21
|
+
CAMERA: 'scope.camera',
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
// ── Result Types ──
|
|
25
|
+
export interface PermissionCheckResult {
|
|
26
|
+
/** Whether the permission is granted. */
|
|
27
|
+
granted: boolean;
|
|
28
|
+
/** Human-readable tip shown to the user. */
|
|
29
|
+
tip: string;
|
|
30
|
+
/**
|
|
31
|
+
* Denial level:
|
|
32
|
+
* - 'mini-program': rejected within this mini-program → wx.openSetting works.
|
|
33
|
+
* - 'system': WeChat lacks the OS permission → user must go to system settings.
|
|
34
|
+
* - 'granted': already authorized.
|
|
35
|
+
*/
|
|
36
|
+
level: 'granted' | 'mini-program' | 'system';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ── Helpers ──
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the raw authSetting snapshot from WeChat.
|
|
43
|
+
*/
|
|
44
|
+
function getAuthSetting(): Promise<any> {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
wx.getSetting({
|
|
48
|
+
success(res: any) {
|
|
49
|
+
resolve(res.authSetting);
|
|
50
|
+
},
|
|
51
|
+
fail() {
|
|
52
|
+
resolve({});
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Attempt to authorize a scope via wx.authorize.
|
|
60
|
+
*/
|
|
61
|
+
function authorizeScope(
|
|
62
|
+
scope: string,
|
|
63
|
+
): Promise<{ success: boolean; errMsg: string }> {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
wx.authorize({
|
|
67
|
+
scope,
|
|
68
|
+
success() {
|
|
69
|
+
resolve({ success: true, errMsg: '' });
|
|
70
|
+
},
|
|
71
|
+
fail(err: any) {
|
|
72
|
+
resolve({ success: false, errMsg: err.errMsg || '' });
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check whether a scope has been explicitly denied by the user at the
|
|
80
|
+
* mini-program level (authSetting returns false for that key).
|
|
81
|
+
*/
|
|
82
|
+
function isMiniProgramDenied(authSetting: any, scope: string): boolean {
|
|
83
|
+
return authSetting[scope] === false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Public API ──
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check and request microphone permission.
|
|
90
|
+
*
|
|
91
|
+
* - No camera permission → calls can still proceed (video call falls back to audio).
|
|
92
|
+
* - No microphone permission → calls MUST be blocked; user is guided to settings.
|
|
93
|
+
*
|
|
94
|
+
* The result's `level` field tells you whether the permission is already
|
|
95
|
+
* granted, denied at the mini-program level (wx.openSetting can fix it),
|
|
96
|
+
* or denied at the system level (user must go to OS settings manually).
|
|
97
|
+
*/
|
|
98
|
+
export async function checkMicrophonePermission(): Promise<PermissionCheckResult> {
|
|
99
|
+
const authSetting = await getAuthSetting();
|
|
100
|
+
|
|
101
|
+
// Already granted
|
|
102
|
+
if (authSetting[PermissionScope.RECORD] === true) {
|
|
103
|
+
return {
|
|
104
|
+
granted: true,
|
|
105
|
+
tip: '',
|
|
106
|
+
level: 'granted',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Mini-program level: user has explicitly rejected the scope before.
|
|
111
|
+
if (isMiniProgramDenied(authSetting, PermissionScope.RECORD)) {
|
|
112
|
+
return {
|
|
113
|
+
granted: false,
|
|
114
|
+
tip: '您已拒绝麦克风权限,请前往小程序设置页面开启麦克风权限后重试',
|
|
115
|
+
level: 'mini-program',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Scope is undefined — never requested. Try to authorize.
|
|
120
|
+
const result = await authorizeScope(PermissionScope.RECORD);
|
|
121
|
+
|
|
122
|
+
if (result.success) {
|
|
123
|
+
return { granted: true, tip: '', level: 'granted' };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Authorization failed.
|
|
127
|
+
// If the native permission dialog was never shown (user actively cancelled
|
|
128
|
+
// or system-level block), errMsg typically contains "auth deny".
|
|
129
|
+
// When the OS-level permission is off, wx.authorize fails immediately
|
|
130
|
+
// without showing the dialog — we treat this as a system-level issue.
|
|
131
|
+
const isSystemLevelDenial =
|
|
132
|
+
!result.errMsg.includes('cancel') &&
|
|
133
|
+
!result.errMsg.includes('deny');
|
|
134
|
+
|
|
135
|
+
// Heuristic: if the error message suggests the dialog did NOT appear,
|
|
136
|
+
// it is very likely a system-level block.
|
|
137
|
+
if (isSystemLevelDenial || result.errMsg.includes('system')) {
|
|
138
|
+
return {
|
|
139
|
+
granted: false,
|
|
140
|
+
tip: '您的微信没有麦克风权限,请前往手机系统设置 > 微信,开启麦克风权限后重试',
|
|
141
|
+
level: 'system',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// User dismissed the native dialog or denied it → mini-program level.
|
|
146
|
+
return {
|
|
147
|
+
granted: false,
|
|
148
|
+
tip: '您拒绝了麦克风权限,请前往小程序设置页面开启麦克风权限后重试',
|
|
149
|
+
level: 'mini-program',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check camera permission.
|
|
155
|
+
*
|
|
156
|
+
* Camera permission is REQUIRED for video calls — a denial MUST block the
|
|
157
|
+
* call (both for initiating and for answering). For audio calls this check
|
|
158
|
+
* is irrelevant and should be skipped by the caller.
|
|
159
|
+
*
|
|
160
|
+
* Tip wording here reflects the blocking policy: it tells the user that
|
|
161
|
+
* video calls cannot proceed without camera permission, and points them to
|
|
162
|
+
* the appropriate settings page (mini-program vs. system level).
|
|
163
|
+
*/
|
|
164
|
+
export async function checkCameraPermission(): Promise<PermissionCheckResult> {
|
|
165
|
+
const authSetting = await getAuthSetting();
|
|
166
|
+
|
|
167
|
+
if (authSetting[PermissionScope.CAMERA] === true) {
|
|
168
|
+
return { granted: true, tip: '', level: 'granted' };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (isMiniProgramDenied(authSetting, PermissionScope.CAMERA)) {
|
|
172
|
+
return {
|
|
173
|
+
granted: false,
|
|
174
|
+
tip: '您已拒绝摄像头权限,无法发起或接听视频通话,请前往小程序设置页面开启摄像头权限后重试',
|
|
175
|
+
level: 'mini-program',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const result = await authorizeScope(PermissionScope.CAMERA);
|
|
180
|
+
|
|
181
|
+
if (result.success) {
|
|
182
|
+
return { granted: true, tip: '', level: 'granted' };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const isSystemLevelDenial =
|
|
186
|
+
!result.errMsg.includes('cancel') &&
|
|
187
|
+
!result.errMsg.includes('deny');
|
|
188
|
+
|
|
189
|
+
if (isSystemLevelDenial || result.errMsg.includes('system')) {
|
|
190
|
+
return {
|
|
191
|
+
granted: false,
|
|
192
|
+
tip: '您的微信没有摄像头权限,无法发起或接听视频通话,请前往手机系统设置 > 微信,开启摄像头权限后重试',
|
|
193
|
+
level: 'system',
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
granted: false,
|
|
199
|
+
tip: '您拒绝了摄像头权限,无法发起或接听视频通话,请前往小程序设置页面开启摄像头权限后重试',
|
|
200
|
+
level: 'mini-program',
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Handle a failed permission check by showing the appropriate dialog and
|
|
206
|
+
* optionally navigating to the settings page.
|
|
207
|
+
*
|
|
208
|
+
* Resolves with `{ confirm }` describing the user's choice:
|
|
209
|
+
* - confirm === true : the user clicked the primary button (前往设置 for the
|
|
210
|
+
* mini-program level, or 我知道了 for the system level).
|
|
211
|
+
* - confirm === false: the user cancelled the dialog (only possible for the
|
|
212
|
+
* mini-program level, which shows a 取消 button).
|
|
213
|
+
*
|
|
214
|
+
* Callers can use this to decide follow-up behavior, e.g. a callee rejecting
|
|
215
|
+
* the incoming call when the user cancels the mandatory permission dialog.
|
|
216
|
+
*/
|
|
217
|
+
export function handlePermissionDenied(result: PermissionCheckResult): Promise<{ confirm: boolean }> {
|
|
218
|
+
return new Promise((resolve) => {
|
|
219
|
+
if (result.level === 'mini-program') {
|
|
220
|
+
// Mini-program level: open the mini-program settings page.
|
|
221
|
+
// @ts-ignore
|
|
222
|
+
wx.showModal({
|
|
223
|
+
title: '权限提示',
|
|
224
|
+
content: result.tip,
|
|
225
|
+
confirmText: '前往设置',
|
|
226
|
+
cancelText: '取消',
|
|
227
|
+
success(modalRes: any) {
|
|
228
|
+
if (modalRes.confirm) {
|
|
229
|
+
// @ts-ignore
|
|
230
|
+
wx.openSetting({
|
|
231
|
+
complete() {
|
|
232
|
+
resolve({ confirm: true });
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
} else {
|
|
236
|
+
resolve({ confirm: false });
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
fail() {
|
|
240
|
+
resolve({ confirm: false });
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
// System level: can only guide the user, cannot open system settings.
|
|
245
|
+
// @ts-ignore
|
|
246
|
+
wx.showModal({
|
|
247
|
+
title: '权限提示',
|
|
248
|
+
content: result.tip,
|
|
249
|
+
showCancel: false,
|
|
250
|
+
confirmText: '我知道了',
|
|
251
|
+
success() {
|
|
252
|
+
resolve({ confirm: true });
|
|
253
|
+
},
|
|
254
|
+
fail() {
|
|
255
|
+
resolve({ confirm: false });
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Combined device-permission pre-check used as the mini-program replacement
|
|
264
|
+
* for `tuiCallEngine.deviceCheck(deviceMap)`.
|
|
265
|
+
*
|
|
266
|
+
* - Microphone is mandatory for every call (audio and video).
|
|
267
|
+
* - Camera is mandatory only for video calls (`deviceMap.camera === true`).
|
|
268
|
+
*
|
|
269
|
+
* When a required permission is missing, the corresponding guidance dialog is
|
|
270
|
+
* shown (via `handlePermissionDenied`) and `false` is returned so the caller
|
|
271
|
+
* can abort / postpone the call. Returns `true` only when all required
|
|
272
|
+
* permissions are granted.
|
|
273
|
+
*/
|
|
274
|
+
export async function checkDevicePermission(
|
|
275
|
+
deviceMap: { microphone?: boolean; camera?: boolean } = {},
|
|
276
|
+
): Promise<boolean> {
|
|
277
|
+
if (deviceMap.microphone) {
|
|
278
|
+
const micResult = await checkMicrophonePermission();
|
|
279
|
+
if (!micResult.granted) {
|
|
280
|
+
await handlePermissionDenied(micResult);
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (deviceMap.camera) {
|
|
286
|
+
const cameraResult = await checkCameraPermission();
|
|
287
|
+
if (!cameraResult.granted) {
|
|
288
|
+
await handlePermissionDenied(cameraResult);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
@@ -17,6 +17,10 @@ export function avoidRepeatedCall() {
|
|
|
17
17
|
if (isCallingSet.has(this)) {
|
|
18
18
|
console.warn((`${NAME.PREFIX}previous ${name}() is ongoing, please avoid repeated calls`));
|
|
19
19
|
// throw new Error(`previous ${name}() is ongoing, please avoid repeated calls`);
|
|
20
|
+
// Guard the method call itself: some classes decorated with
|
|
21
|
+
// `avoidRepeatedCall` (e.g. CallManager) do not implement
|
|
22
|
+
// `getTUICallEngineInstance`. Using `?.()` short-circuits when the
|
|
23
|
+
// method is absent instead of throwing "is not a function".
|
|
20
24
|
this?.getTUICallEngineInstance()?.reportLog?.({
|
|
21
25
|
name: 'TUICallKit.avoidRepeatedCall.fail',
|
|
22
26
|
data: { name },
|
|
@@ -38,7 +42,7 @@ export function avoidRepeatedCall() {
|
|
|
38
42
|
descriptor.value.clearCallState = function(instance: any) {
|
|
39
43
|
isCallingSet.delete(instance);
|
|
40
44
|
};
|
|
41
|
-
|
|
45
|
+
|
|
42
46
|
return descriptor;
|
|
43
47
|
};
|
|
44
48
|
}
|