@zfqh/uniapp-x 0.0.0-stage → 0.0.1
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/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +61 -3
- package/lib/apis/core.d.ts +18 -0
- package/lib/apis/core.js +19 -0
- package/lib/apis/index.d.ts +2 -0
- package/lib/apis/index.js +2 -0
- package/lib/apis/request.d.ts +4 -0
- package/lib/apis/request.js +57 -0
- package/lib/configs/api.d.ts +7 -0
- package/lib/configs/api.js +6 -0
- package/lib/configs/app.d.ts +20 -0
- package/lib/configs/app.js +18 -0
- package/lib/configs/cdn.d.ts +15 -0
- package/lib/configs/cdn.js +17 -0
- package/lib/configs/env.d.ts +37 -0
- package/lib/configs/env.js +71 -0
- package/lib/configs/index.d.ts +130 -0
- package/lib/configs/index.js +76 -0
- package/lib/configs/link.d.ts +11 -0
- package/lib/configs/link.js +3 -0
- package/lib/configs/log.d.ts +9 -0
- package/lib/configs/log.js +8 -0
- package/lib/configs/mp.d.ts +15 -0
- package/lib/configs/mp.js +9 -0
- package/lib/configs/navigate.d.ts +17 -0
- package/lib/configs/navigate.js +5 -0
- package/lib/configs/page.d.ts +18 -0
- package/lib/configs/page.js +14 -0
- package/lib/configs/path.d.ts +11 -0
- package/lib/configs/path.js +10 -0
- package/lib/configs/storage.d.ts +7 -0
- package/lib/configs/storage.js +6 -0
- package/lib/configs/tabbar.d.ts +7 -0
- package/lib/configs/tabbar.js +6 -0
- package/lib/configs/toast.d.ts +18 -0
- package/lib/configs/toast.js +29 -0
- package/lib/configs/updater.d.ts +15 -0
- package/lib/configs/updater.js +33 -0
- package/lib/configs/upload.d.ts +30 -0
- package/lib/configs/upload.js +19 -0
- package/lib/configs/ver.d.ts +8 -0
- package/lib/configs/ver.js +28 -0
- package/lib/configs/web.d.ts +5 -0
- package/lib/configs/web.js +2 -0
- package/lib/hooks/index.d.ts +11 -0
- package/lib/hooks/index.js +11 -0
- package/lib/hooks/useAppLifecycle.d.ts +8 -0
- package/lib/hooks/useAppLifecycle.js +87 -0
- package/lib/hooks/useBadge.d.ts +8 -0
- package/lib/hooks/useBadge.js +47 -0
- package/lib/hooks/useNeedLogin.d.ts +1 -0
- package/lib/hooks/useNeedLogin.js +27 -0
- package/lib/hooks/useOverlay.d.ts +1 -0
- package/lib/hooks/useOverlay.js +17 -0
- package/lib/hooks/usePageShow.d.ts +2 -0
- package/lib/hooks/usePageShow.js +16 -0
- package/lib/hooks/usePopup.d.ts +1 -0
- package/lib/hooks/usePopup.js +14 -0
- package/lib/hooks/useRedirect.d.ts +5 -0
- package/lib/hooks/useRedirect.js +92 -0
- package/lib/hooks/useReferrer.d.ts +1 -0
- package/lib/hooks/useReferrer.js +11 -0
- package/lib/hooks/useShare.d.ts +12 -0
- package/lib/hooks/useShare.js +49 -0
- package/lib/hooks/useVersion.d.ts +6 -0
- package/lib/hooks/useVersion.js +21 -0
- package/lib/hooks/useWebview.d.ts +14 -0
- package/lib/hooks/useWebview.js +294 -0
- package/lib/index.d.ts +27 -0
- package/lib/index.js +26 -0
- package/lib/stores/app.d.ts +51 -0
- package/lib/stores/app.js +57 -0
- package/lib/stores/dict.d.ts +35 -0
- package/lib/stores/dict.js +42 -0
- package/lib/stores/im.d.ts +57 -0
- package/lib/stores/im.js +102 -0
- package/lib/stores/index.d.ts +12 -0
- package/lib/stores/index.js +17 -0
- package/lib/stores/launch.d.ts +42 -0
- package/lib/stores/launch.js +39 -0
- package/lib/stores/location.d.ts +35 -0
- package/lib/stores/location.js +58 -0
- package/lib/stores/login.d.ts +80 -0
- package/lib/stores/login.js +91 -0
- package/lib/stores/network.d.ts +26 -0
- package/lib/stores/network.js +45 -0
- package/lib/stores/pinia.d.ts +2 -0
- package/lib/stores/pinia.js +3 -0
- package/lib/stores/system.d.ts +39 -0
- package/lib/stores/system.js +36 -0
- package/lib/styles/index.scss +9 -0
- package/lib/styles/reset-vue.scss +15 -0
- package/lib/utils/audio.d.ts +14 -0
- package/lib/utils/audio.js +43 -0
- package/lib/utils/consts.d.ts +74 -0
- package/lib/utils/consts.js +110 -0
- package/lib/utils/cos.d.ts +17 -0
- package/lib/utils/cos.js +141 -0
- package/lib/utils/file.d.ts +28 -0
- package/lib/utils/file.js +292 -0
- package/lib/utils/index.d.ts +166 -0
- package/lib/utils/index.js +486 -0
- package/lib/utils/message.d.ts +1 -0
- package/lib/utils/message.js +55 -0
- package/lib/utils/navigate.d.ts +28 -0
- package/lib/utils/navigate.js +192 -0
- package/lib/utils/pages.d.ts +21 -0
- package/lib/utils/pages.js +83 -0
- package/lib/utils/permission.d.ts +17 -0
- package/lib/utils/permission.js +278 -0
- package/lib/utils/query.d.ts +20 -0
- package/lib/utils/query.js +51 -0
- package/lib/utils/request.d.ts +8 -0
- package/lib/utils/request.js +139 -0
- package/lib/utils/storage.d.ts +40 -0
- package/lib/utils/storage.js +128 -0
- package/lib/utils/subscribe.d.ts +7 -0
- package/lib/utils/subscribe.js +94 -0
- package/lib/utils/toast.d.ts +17 -0
- package/lib/utils/toast.js +66 -0
- package/lib/utils/uni.d.ts +1 -0
- package/lib/utils/uni.js +141 -0
- package/lib/utils/update.d.ts +41 -0
- package/lib/utils/update.js +322 -0
- package/lib/utils/url.d.ts +14 -0
- package/lib/utils/url.js +40 -0
- package/package.json +38 -4
- package/types/index.d.ts +78 -0
- package/types/virtual.d.ts +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { queryParams } from '@zfqh/uview-x/utils/function';
|
|
2
|
+
import page from '../configs/page';
|
|
3
|
+
import nav from '../configs/navigate';
|
|
4
|
+
import app from '../configs/app';
|
|
5
|
+
import { IS_WEBVIEW_ENV, WEBVIEW_ENV } from './consts';
|
|
6
|
+
import { inPages, getPage } from './pages';
|
|
7
|
+
import { joinPath } from './index';
|
|
8
|
+
import { pinia } from '../stores/pinia';
|
|
9
|
+
import { useLoginStore } from '../stores/login';
|
|
10
|
+
// 检测协议路�?
|
|
11
|
+
const checkProtocolMatch = (url) => url.match(/^([\w.]+):\//);
|
|
12
|
+
// 转换绝对路径
|
|
13
|
+
const getAbsoUrl = (url, current) => {
|
|
14
|
+
if (!url.startsWith('/') && !checkProtocolMatch(url)) {
|
|
15
|
+
url = joinPath(current, url);
|
|
16
|
+
if (!url.startsWith('/')) {
|
|
17
|
+
url = `/${url}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return url;
|
|
21
|
+
};
|
|
22
|
+
// 节流,防止重复执�?
|
|
23
|
+
let throttling = false;
|
|
24
|
+
const navigate = function (url = '', type = 'navigateTo') {
|
|
25
|
+
if (!throttling) {
|
|
26
|
+
throttling = true;
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
throttling = false;
|
|
29
|
+
}, 500);
|
|
30
|
+
let needLogin = false;
|
|
31
|
+
let isNative = !page.pages?.length;
|
|
32
|
+
let navigateOptions = {};
|
|
33
|
+
let webviewParams = {};
|
|
34
|
+
let webviewPage = getPage('webview');
|
|
35
|
+
let loginType = nav.loginType;
|
|
36
|
+
let referrerType = nav.referrerType;
|
|
37
|
+
let opts = {};
|
|
38
|
+
if (typeof url === 'string') {
|
|
39
|
+
url = { url };
|
|
40
|
+
}
|
|
41
|
+
if (typeof url === 'object') {
|
|
42
|
+
opts = url;
|
|
43
|
+
const { type: _type, url: _url = '', params: _params = {}, webviewParams: _webviewParams = {}, webviewUrl: _webviewPage = webviewPage, needLogin: _needLogin = needLogin, loginType: _loginType = loginType, referrerType: _referrerType = referrerType, native: _isNative = isNative, ...rest } = url;
|
|
44
|
+
url = `${_url}${queryParams(_params)}`;
|
|
45
|
+
needLogin = !!_needLogin;
|
|
46
|
+
isNative = !!_isNative;
|
|
47
|
+
loginType = _loginType;
|
|
48
|
+
referrerType = _referrerType;
|
|
49
|
+
type = _type || type;
|
|
50
|
+
webviewParams = _webviewParams;
|
|
51
|
+
webviewPage = _webviewPage;
|
|
52
|
+
navigateOptions = rest;
|
|
53
|
+
}
|
|
54
|
+
const indexPage = getPage('index').replace(/^\/+/, '');
|
|
55
|
+
const loginPage = getPage('login');
|
|
56
|
+
const { isLogin } = useLoginStore(pinia);
|
|
57
|
+
const { route = indexPage, options = {} } = (getCurrentPages().pop() || {});
|
|
58
|
+
const current = `/${route}${queryParams(options)}`;
|
|
59
|
+
let absoUrl = getAbsoUrl(url, current);
|
|
60
|
+
let originalUrl = url;
|
|
61
|
+
url = navigate.interceptor.call(this, url, absoUrl);
|
|
62
|
+
if (typeof url !== 'string') {
|
|
63
|
+
throttling = false;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (originalUrl !== url) {
|
|
67
|
+
originalUrl = url;
|
|
68
|
+
absoUrl = getAbsoUrl(url, current);
|
|
69
|
+
}
|
|
70
|
+
if (!originalUrl) {
|
|
71
|
+
if (isLogin) {
|
|
72
|
+
throttling = false;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// 跳转地址为空表示需要登�?
|
|
76
|
+
needLogin = true;
|
|
77
|
+
}
|
|
78
|
+
// 路径转为绝对路径
|
|
79
|
+
url = absoUrl;
|
|
80
|
+
// 是否需要登�?
|
|
81
|
+
if (!needLogin) {
|
|
82
|
+
needLogin = inPages(page.needLoginPages, url);
|
|
83
|
+
}
|
|
84
|
+
// 是否是原生页�?
|
|
85
|
+
if (!isNative && url.startsWith('/')) {
|
|
86
|
+
isNative = inPages(page.nativePages, url);
|
|
87
|
+
}
|
|
88
|
+
if (!isNative) {
|
|
89
|
+
if (!checkProtocolMatch(url)) {
|
|
90
|
+
if (app?.code) {
|
|
91
|
+
url = `${app.code}:/${url}`;
|
|
92
|
+
}
|
|
93
|
+
else if (app?.appId) {
|
|
94
|
+
url = `${app.appId}:/${url}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (IS_WEBVIEW_ENV && opts['native'] === false) {
|
|
99
|
+
isNative = false;
|
|
100
|
+
}
|
|
101
|
+
const protocolMatch = checkProtocolMatch(url);
|
|
102
|
+
// 带协议路径需要转换为webview方式加载
|
|
103
|
+
if (protocolMatch) {
|
|
104
|
+
isNative = true;
|
|
105
|
+
const params = Object.assign({}, webviewParams);
|
|
106
|
+
if (/^https?:/.test(url)) {
|
|
107
|
+
// #ifdef H5
|
|
108
|
+
// 一些网站同源策略,无法iframe中打开
|
|
109
|
+
if ((WEBVIEW_ENV.h5 || !IS_WEBVIEW_ENV) && ['mp.weixin.qq.com'].includes(new URL(url).hostname)) {
|
|
110
|
+
top.location.href = url;
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
// #endif
|
|
114
|
+
// http协议
|
|
115
|
+
Object.assign(params, { url: encodeURIComponent(url) });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// 自定义协�?
|
|
119
|
+
url = url.replace(new RegExp(`^(${protocolMatch[0]})`), '');
|
|
120
|
+
Object.assign(params, { url: encodeURIComponent(url), app: protocolMatch[1] });
|
|
121
|
+
}
|
|
122
|
+
url = `${webviewPage}${queryParams(params)}`;
|
|
123
|
+
}
|
|
124
|
+
if (needLogin) {
|
|
125
|
+
if (!isLogin) {
|
|
126
|
+
const opts = {
|
|
127
|
+
url: loginPage,
|
|
128
|
+
};
|
|
129
|
+
if (referrerType === 'combine') {
|
|
130
|
+
// 登录后会先跳转到来源页面,再跳转目标页面
|
|
131
|
+
if (url !== current) {
|
|
132
|
+
url = `/${route}${queryParams({ ...options, __navigate: encodeURIComponent(url) })}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (referrerType === 'referrer') {
|
|
136
|
+
// 登录后跳转到来源页面
|
|
137
|
+
url = current;
|
|
138
|
+
}
|
|
139
|
+
else if (referrerType === 'target') {
|
|
140
|
+
// 登录后跳转到目标页面
|
|
141
|
+
}
|
|
142
|
+
if (['target', 'referrer', 'combine'].includes(referrerType)) {
|
|
143
|
+
opts.url += `${opts.url.includes('?') ? '&' : '?'}__referrer=${encodeURIComponent(url)}`;
|
|
144
|
+
}
|
|
145
|
+
if (uni.webView && IS_WEBVIEW_ENV) {
|
|
146
|
+
uni.webView[loginType](opts);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
uni[loginType](opts);
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (originalUrl) {
|
|
155
|
+
if (inPages(page.tabBarPages, url)) {
|
|
156
|
+
if (['navigateTo', 'redirectTo'].includes(type)) {
|
|
157
|
+
type = 'switchTab';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (isNative && uni.webView && IS_WEBVIEW_ENV) {
|
|
161
|
+
uni.webView[type]({
|
|
162
|
+
url,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
uni[type]({
|
|
167
|
+
url,
|
|
168
|
+
...navigateOptions,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
navigate.reLaunch = (url) => {
|
|
175
|
+
navigate(url, 'reLaunch');
|
|
176
|
+
};
|
|
177
|
+
navigate.navigateTo = (url) => {
|
|
178
|
+
navigate(url, 'navigateTo');
|
|
179
|
+
};
|
|
180
|
+
navigate.switchTab = (url) => {
|
|
181
|
+
navigate(url, 'switchTab');
|
|
182
|
+
};
|
|
183
|
+
navigate.redirectTo = (url) => {
|
|
184
|
+
navigate(url, 'redirectTo');
|
|
185
|
+
};
|
|
186
|
+
navigate.back = (e) => {
|
|
187
|
+
uni.navigateBack(e);
|
|
188
|
+
};
|
|
189
|
+
navigate.interceptor = (...args) => {
|
|
190
|
+
return args[0];
|
|
191
|
+
};
|
|
192
|
+
export default navigate;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const getPage: (name: string) => string;
|
|
2
|
+
export declare const inPages: (pages: string[], url: string | {
|
|
3
|
+
url: string;
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}) => boolean;
|
|
6
|
+
export declare const createPages: (original?: {
|
|
7
|
+
pages?: any[];
|
|
8
|
+
subPackages?: any[];
|
|
9
|
+
tabBar?: any;
|
|
10
|
+
global?: {
|
|
11
|
+
native?: boolean;
|
|
12
|
+
needLogin?: boolean;
|
|
13
|
+
notRedirect?: boolean;
|
|
14
|
+
};
|
|
15
|
+
}, basePath?: string) => {
|
|
16
|
+
pages: string[];
|
|
17
|
+
tabBarPages: string[];
|
|
18
|
+
nativePages: string[];
|
|
19
|
+
needLoginPages: string[];
|
|
20
|
+
notRedirectPages: string[];
|
|
21
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from '../configs/path';
|
|
2
|
+
export const getPage = (name) => {
|
|
3
|
+
let page = '';
|
|
4
|
+
if (path[name]) {
|
|
5
|
+
page = path[name];
|
|
6
|
+
}
|
|
7
|
+
return page;
|
|
8
|
+
};
|
|
9
|
+
export const inPages = (pages, url) => {
|
|
10
|
+
if (typeof url === 'object') {
|
|
11
|
+
url = url.url;
|
|
12
|
+
}
|
|
13
|
+
if (!Array.isArray(pages) || !url || typeof url !== 'string') {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
return pages.some((page) => {
|
|
17
|
+
page = String(page);
|
|
18
|
+
const [path] = page.split('**');
|
|
19
|
+
if (path !== page) {
|
|
20
|
+
return url.startsWith(path);
|
|
21
|
+
}
|
|
22
|
+
return url.replace(/\?.*$/, '') === path;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
export const createPages = (original = {}, basePath = '') => {
|
|
26
|
+
const pages = [];
|
|
27
|
+
const tabBarPages = [];
|
|
28
|
+
const nativePages = [];
|
|
29
|
+
const needLoginPages = [];
|
|
30
|
+
const notRedirectPages = [];
|
|
31
|
+
const create = ({ path: p, root, ...rest }) => {
|
|
32
|
+
if (p) {
|
|
33
|
+
const { native, needLogin, notRedirect } = { ...original.global, ...rest };
|
|
34
|
+
const { name } = rest;
|
|
35
|
+
const array = [''];
|
|
36
|
+
if (basePath) {
|
|
37
|
+
array.push(basePath);
|
|
38
|
+
}
|
|
39
|
+
if (root && basePath !== `/${root}`) {
|
|
40
|
+
array.push(root);
|
|
41
|
+
}
|
|
42
|
+
array.push(p);
|
|
43
|
+
const page = array.join('/').replace(/\/+/, '/');
|
|
44
|
+
pages.push(page);
|
|
45
|
+
if (name) {
|
|
46
|
+
path[name] = page;
|
|
47
|
+
}
|
|
48
|
+
if (native || native == null) {
|
|
49
|
+
nativePages.push(page);
|
|
50
|
+
}
|
|
51
|
+
if (needLogin) {
|
|
52
|
+
needLoginPages.push(page);
|
|
53
|
+
}
|
|
54
|
+
if (notRedirect) {
|
|
55
|
+
notRedirectPages.push(page);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
if (original.pages) {
|
|
60
|
+
original.pages.forEach((page) => {
|
|
61
|
+
create(page);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (original.subPackages) {
|
|
65
|
+
original.subPackages.forEach(({ root, pages: list }) => {
|
|
66
|
+
list.forEach((page) => {
|
|
67
|
+
create(Object.assign(page, { root }));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (original.tabBar && original.tabBar.list) {
|
|
72
|
+
original.tabBar.list.forEach(({ pagePath }) => {
|
|
73
|
+
tabBarPages.push(`/${pagePath}`);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
pages,
|
|
78
|
+
tabBarPages,
|
|
79
|
+
nativePages,
|
|
80
|
+
needLoginPages,
|
|
81
|
+
notRedirectPages,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type PermissionName = 'location' | 'storage' | 'camera' | 'record' | 'bluetooth';
|
|
2
|
+
/**
|
|
3
|
+
* 打开权限设置
|
|
4
|
+
* - 经典 App:plus 打开系统设置页(定位 / 蓝牙总开关)
|
|
5
|
+
* - uni-app x App:uni.openAppAuthorizeSetting 打开应用授权设置页
|
|
6
|
+
* - H5 webview:向宿主发送消息
|
|
7
|
+
* - 小程序:uni.openAppAuthorizeSetting
|
|
8
|
+
*/
|
|
9
|
+
export declare function openAuthorizeSetting(name: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* 申请权限
|
|
12
|
+
* @param name 权限名称
|
|
13
|
+
* @param system 是否同时检查定位 / 蓝牙的系统级开关
|
|
14
|
+
* @returns 允许时 resolve(1);未授权或系统开关关闭时 reject(0)
|
|
15
|
+
*/
|
|
16
|
+
export declare function requestPermission(name: PermissionName, system?: boolean): Promise<number>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 权限申请
|
|
3
|
+
* - 经典 App(APP-PLUS):plus.android.requestPermissions(Android)+ uni.getSystemSetting
|
|
4
|
+
* - uni-app x App(APP + UNI-APP-X):uni.requestSystemPermission(Android 5.25+)+ uni.getSystemSetting
|
|
5
|
+
* - 小程序:uni.authorize / uni.openSetting
|
|
6
|
+
* - H5:webview 内通过 postMessage 通知宿主
|
|
7
|
+
*/
|
|
8
|
+
import { config } from '@zfqh/uview-x';
|
|
9
|
+
import { SYSTEM_INFO, IS_WEBVIEW_ENV, TYPES } from './consts';
|
|
10
|
+
import { postMessage } from './index';
|
|
11
|
+
const permissionData = {
|
|
12
|
+
location: {
|
|
13
|
+
// #ifdef APP
|
|
14
|
+
system: '检测到系统未开启定位',
|
|
15
|
+
// #endif
|
|
16
|
+
content: '我们需要获取您的定位权限,用于城市定位、地址获取、位置获取,发现附近设备等服务',
|
|
17
|
+
},
|
|
18
|
+
storage: {
|
|
19
|
+
// #ifdef APP
|
|
20
|
+
system: '',
|
|
21
|
+
// #endif
|
|
22
|
+
content: '我们需要获取您的文件存储权限,用于设置头像、保存图片、上传文件、发布内容等服务',
|
|
23
|
+
},
|
|
24
|
+
camera: {
|
|
25
|
+
// #ifdef APP
|
|
26
|
+
system: '',
|
|
27
|
+
// #endif
|
|
28
|
+
content: '我们需要获取您的相机权限,用于拍摄照片、录制视频、视频通话、扫码识别、发布内容等服务',
|
|
29
|
+
},
|
|
30
|
+
record: {
|
|
31
|
+
// #ifdef APP
|
|
32
|
+
system: '',
|
|
33
|
+
// #endif
|
|
34
|
+
content: '我们需要获取您的麦克风权限,用于录制语音、语音通话,发布内容等服务',
|
|
35
|
+
},
|
|
36
|
+
bluetooth: {
|
|
37
|
+
// #ifdef APP
|
|
38
|
+
system: '检测到系统未开启蓝牙',
|
|
39
|
+
// #endif
|
|
40
|
+
content: '我们需要获取您的蓝牙权限,用于数据传输、设备配对、发现附近设备等服务',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
// #ifdef APP
|
|
44
|
+
// Android 系统 API 版本:蓝牙、存储在 Android 10 / 12 以上需要的权限不同
|
|
45
|
+
const ANDROID_API_LEVEL = Number(uni.getSystemInfoSync().osAndroidAPILevel) || 0;
|
|
46
|
+
// #ifdef APP-PLUS
|
|
47
|
+
const CLASSIC_ANDROID_PERMISSIONS = {
|
|
48
|
+
location: ['android.permission.ACCESS_FINE_LOCATION'],
|
|
49
|
+
storage: ['android.permission.WRITE_EXTERNAL_STORAGE'],
|
|
50
|
+
camera: ['android.permission.CAMERA'],
|
|
51
|
+
record: ['android.permission.RECORD_AUDIO'],
|
|
52
|
+
bluetooth: ANDROID_API_LEVEL >= 31
|
|
53
|
+
? ['android.permission.BLUETOOTH_SCAN', 'android.permission.BLUETOOTH_CONNECT']
|
|
54
|
+
: ['android.permission.BLUETOOTH'],
|
|
55
|
+
};
|
|
56
|
+
// #endif
|
|
57
|
+
// #ifdef UNI-APP-X
|
|
58
|
+
const UNI_APP_X_ANDROID_PERMISSIONS = {
|
|
59
|
+
location: ['android.permission.ACCESS_FINE_LOCATION', 'android.permission.ACCESS_COARSE_LOCATION'],
|
|
60
|
+
// Android 10+ 使用分区存储,无需申请 WRITE_EXTERNAL_STORAGE
|
|
61
|
+
storage: ANDROID_API_LEVEL < 29 ? ['android.permission.WRITE_EXTERNAL_STORAGE'] : [],
|
|
62
|
+
camera: ['android.permission.CAMERA'],
|
|
63
|
+
record: ['android.permission.RECORD_AUDIO'],
|
|
64
|
+
bluetooth: ANDROID_API_LEVEL >= 31
|
|
65
|
+
? ['android.permission.BLUETOOTH_SCAN', 'android.permission.BLUETOOTH_CONNECT']
|
|
66
|
+
: ['android.permission.BLUETOOTH'],
|
|
67
|
+
};
|
|
68
|
+
// #endif
|
|
69
|
+
// #endif
|
|
70
|
+
// #ifdef APP-PLUS
|
|
71
|
+
const requestAndroidPermission = async (name) => {
|
|
72
|
+
const permissions = CLASSIC_ANDROID_PERMISSIONS[name];
|
|
73
|
+
if (!permissions.length) {
|
|
74
|
+
return 1;
|
|
75
|
+
}
|
|
76
|
+
uni.showAppFromBackground = false;
|
|
77
|
+
return await new Promise((resolve) => {
|
|
78
|
+
plus.android.requestPermissions(permissions, (result) => {
|
|
79
|
+
if (result.deniedAlways?.length) {
|
|
80
|
+
resolve(-1);
|
|
81
|
+
}
|
|
82
|
+
else if (result.deniedPresent?.length) {
|
|
83
|
+
resolve(0);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
resolve(1);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
// 申请失败时无法预判,交给实际能力调用时系统弹窗
|
|
90
|
+
() => resolve(1));
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
// #endif
|
|
94
|
+
// #ifdef APP
|
|
95
|
+
// #ifdef UNI-APP-X
|
|
96
|
+
const requestUniAppXPermission = async (name) => {
|
|
97
|
+
// #ifdef APP-ANDROID
|
|
98
|
+
if (typeof uni.requestSystemPermission === 'function') {
|
|
99
|
+
const permissions = UNI_APP_X_ANDROID_PERMISSIONS[name];
|
|
100
|
+
if (permissions.length) {
|
|
101
|
+
uni.showAppFromBackground = false;
|
|
102
|
+
return await new Promise((resolve) => {
|
|
103
|
+
uni.requestSystemPermission({
|
|
104
|
+
permissions,
|
|
105
|
+
success: (result) => {
|
|
106
|
+
if (result.doNotAskAgainList.length) {
|
|
107
|
+
resolve(-1);
|
|
108
|
+
}
|
|
109
|
+
else if (result.deniedList.length) {
|
|
110
|
+
resolve(0);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
resolve(1);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
// 无法预申请(低版本、权限未声明等)时交给实际能力调用时系统弹窗
|
|
117
|
+
fail: () => resolve(1),
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// #endif
|
|
123
|
+
return 1;
|
|
124
|
+
};
|
|
125
|
+
// #endif
|
|
126
|
+
// #endif
|
|
127
|
+
// #ifdef MP
|
|
128
|
+
const requestMpPermission = async (scope) => {
|
|
129
|
+
return await new Promise((res) => {
|
|
130
|
+
uni.authorize({
|
|
131
|
+
scope,
|
|
132
|
+
success() {
|
|
133
|
+
res(1);
|
|
134
|
+
},
|
|
135
|
+
fail() {
|
|
136
|
+
res(0);
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
// #endif
|
|
142
|
+
// 系统级开关:经典 App 与 uni-app x App 统一使用官方 uni.getSystemSetting
|
|
143
|
+
const isSystemEnabled = (name) => {
|
|
144
|
+
// #ifdef APP
|
|
145
|
+
const setting = uni.getSystemSetting();
|
|
146
|
+
if (name === 'location') {
|
|
147
|
+
// iOS 模块未配置时 locationError 非空,不阻塞业务
|
|
148
|
+
return !!setting.locationError || setting.locationEnabled;
|
|
149
|
+
}
|
|
150
|
+
if (name === 'bluetooth') {
|
|
151
|
+
// iOS 与经典 App 保持一致交给系统;Android 权限或模块配置错误不误导用户去设置
|
|
152
|
+
return SYSTEM_INFO.platform === 'ios' || !!setting.bluetoothError || setting.bluetoothEnabled !== false;
|
|
153
|
+
}
|
|
154
|
+
// #endif
|
|
155
|
+
return true;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* 打开权限设置
|
|
159
|
+
* - 经典 App:plus 打开系统设置页(定位 / 蓝牙总开关)
|
|
160
|
+
* - uni-app x App:uni.openAppAuthorizeSetting 打开应用授权设置页
|
|
161
|
+
* - H5 webview:向宿主发送消息
|
|
162
|
+
* - 小程序:uni.openAppAuthorizeSetting
|
|
163
|
+
*/
|
|
164
|
+
export function openAuthorizeSetting(name) {
|
|
165
|
+
// #ifdef H5
|
|
166
|
+
if (IS_WEBVIEW_ENV) {
|
|
167
|
+
postMessage({
|
|
168
|
+
type: name === 'location' ? TYPES.MESSAGE.PERM_LOCATION : TYPES.MESSAGE.PERM_BLUETOOTH,
|
|
169
|
+
payload: { name },
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// #endif
|
|
173
|
+
// #ifdef APP-PLUS
|
|
174
|
+
if (SYSTEM_INFO.platform == 'ios') {
|
|
175
|
+
plus.runtime.openURL('app-settings://');
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const main = plus.android.runtimeMainActivity();
|
|
179
|
+
const Intent = plus.android.importClass('android.content.Intent');
|
|
180
|
+
const Settings = plus.android.importClass('android.provider.Settings');
|
|
181
|
+
let intent = null;
|
|
182
|
+
if (name === 'location') {
|
|
183
|
+
intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
|
|
184
|
+
}
|
|
185
|
+
else if (name === 'bluetooth') {
|
|
186
|
+
intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
|
|
187
|
+
}
|
|
188
|
+
if (intent) {
|
|
189
|
+
main.startActivity(intent);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// #endif
|
|
193
|
+
// #ifdef APP
|
|
194
|
+
// #ifdef UNI-APP-X
|
|
195
|
+
if (typeof uni.openAppAuthorizeSetting === 'function') {
|
|
196
|
+
uni.openAppAuthorizeSetting({});
|
|
197
|
+
}
|
|
198
|
+
// #endif
|
|
199
|
+
// #endif
|
|
200
|
+
// #ifdef MP
|
|
201
|
+
uni.openAppAuthorizeSetting();
|
|
202
|
+
// #endif
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 申请权限
|
|
206
|
+
* @param name 权限名称
|
|
207
|
+
* @param system 是否同时检查定位 / 蓝牙的系统级开关
|
|
208
|
+
* @returns 允许时 resolve(1);未授权或系统开关关闭时 reject(0)
|
|
209
|
+
*/
|
|
210
|
+
export async function requestPermission(name, system = true) {
|
|
211
|
+
let result = 1;
|
|
212
|
+
// #ifdef MP
|
|
213
|
+
switch (name) {
|
|
214
|
+
case 'location': {
|
|
215
|
+
result = await requestMpPermission('scope.userLocation');
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case 'storage': {
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
default: {
|
|
222
|
+
result = await requestMpPermission(`scope.${name}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// #endif
|
|
226
|
+
// #ifdef APP-PLUS
|
|
227
|
+
if (SYSTEM_INFO.platform === 'android') {
|
|
228
|
+
result = await requestAndroidPermission(name);
|
|
229
|
+
}
|
|
230
|
+
// #endif
|
|
231
|
+
// #ifdef APP
|
|
232
|
+
// #ifdef UNI-APP-X
|
|
233
|
+
result = await requestUniAppXPermission(name);
|
|
234
|
+
// #endif
|
|
235
|
+
// #endif
|
|
236
|
+
if (system && result > 0 && !isSystemEnabled(name)) {
|
|
237
|
+
result = -2;
|
|
238
|
+
}
|
|
239
|
+
if (result <= 0) {
|
|
240
|
+
const { content, system: systemTips } = permissionData[name];
|
|
241
|
+
uni.showModal({
|
|
242
|
+
title: '提示',
|
|
243
|
+
content: `${result === -2 ? systemTips : `${content},检测到应用未开启权限`},是否开启?`,
|
|
244
|
+
confirmText: '去开启',
|
|
245
|
+
cancelText: '取消',
|
|
246
|
+
confirmColor: config.color.primary,
|
|
247
|
+
cancelColor: config.color.tipsColor,
|
|
248
|
+
success: (res) => {
|
|
249
|
+
if (res.confirm) {
|
|
250
|
+
try {
|
|
251
|
+
// #ifdef MP
|
|
252
|
+
uni.openSetting();
|
|
253
|
+
// #endif
|
|
254
|
+
// #ifdef APP-PLUS
|
|
255
|
+
uni.showAppFromBackground = false;
|
|
256
|
+
// app开启权限,系统没有开启
|
|
257
|
+
if (result === -2) {
|
|
258
|
+
openAuthorizeSetting(name);
|
|
259
|
+
// 系统开启权限,app没有开启
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
uni.openAppAuthorizeSetting();
|
|
263
|
+
}
|
|
264
|
+
// #endif
|
|
265
|
+
// #ifdef APP
|
|
266
|
+
// #ifdef UNI-APP-X
|
|
267
|
+
openAuthorizeSetting(name);
|
|
268
|
+
// #endif
|
|
269
|
+
// #endif
|
|
270
|
+
}
|
|
271
|
+
catch (e) { }
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
return Promise.reject(0);
|
|
276
|
+
}
|
|
277
|
+
return Promise.resolve(1);
|
|
278
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface Query {
|
|
2
|
+
platform?: string;
|
|
3
|
+
channel?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
accessToken?: string;
|
|
6
|
+
primary?: string;
|
|
7
|
+
app?: string;
|
|
8
|
+
safeTop?: string | number;
|
|
9
|
+
safeBottom?: string | number;
|
|
10
|
+
tabbar?: string | number;
|
|
11
|
+
accelerate?: string | number;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
declare const query: Query;
|
|
15
|
+
export declare function parseQuery(search?: string): Query;
|
|
16
|
+
/** 将对象序列化为 query string(供 webview 参数拼装使用,避免依赖 qs)。 */
|
|
17
|
+
export declare function stringifyQuery(data: Record<string, any>, options?: {
|
|
18
|
+
encode?: boolean;
|
|
19
|
+
}): string;
|
|
20
|
+
export default query;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const query = {};
|
|
2
|
+
export function parseQuery(search = '') {
|
|
3
|
+
const q = {};
|
|
4
|
+
search.split('&').forEach((value) => {
|
|
5
|
+
if (!value)
|
|
6
|
+
return;
|
|
7
|
+
const [key, val] = value.split('=');
|
|
8
|
+
q[key] = decodeURIComponent(val);
|
|
9
|
+
});
|
|
10
|
+
return q;
|
|
11
|
+
}
|
|
12
|
+
/** 将对象序列化为 query string(供 webview 参数拼装使用,避免依赖 qs)。 */
|
|
13
|
+
export function stringifyQuery(data, options = {}) {
|
|
14
|
+
const shouldEncode = options.encode !== false;
|
|
15
|
+
const parts = [];
|
|
16
|
+
const append = (key, value) => {
|
|
17
|
+
if (value === undefined || value === null)
|
|
18
|
+
return;
|
|
19
|
+
const k = shouldEncode ? encodeURIComponent(key) : key;
|
|
20
|
+
const v = shouldEncode ? encodeURIComponent(String(value)) : String(value);
|
|
21
|
+
parts.push(`${k}=${v}`);
|
|
22
|
+
};
|
|
23
|
+
Object.keys(data || {}).forEach((key) => {
|
|
24
|
+
const value = data[key];
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
value.forEach((item) => append(key, item));
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
append(key, value);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return parts.join('&');
|
|
33
|
+
}
|
|
34
|
+
// #ifdef H5
|
|
35
|
+
Object.assign(query, parseQuery(location.search.substring(1)));
|
|
36
|
+
const safeTop = Number(query.safeTop);
|
|
37
|
+
const safeBottom = Number(query.safeBottom);
|
|
38
|
+
if (safeTop > 0) {
|
|
39
|
+
query.safeTop = safeTop;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
query.safeTop = 0;
|
|
43
|
+
}
|
|
44
|
+
if (safeBottom > 0) {
|
|
45
|
+
query.safeBottom = safeBottom;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
query.safeBottom = 0;
|
|
49
|
+
}
|
|
50
|
+
// #endif
|
|
51
|
+
export default query;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function formatURL(url: any, data: any): string;
|
|
2
|
+
export declare function createInterceptors(req: any): void;
|
|
3
|
+
export declare function createRequest(req: any, _opts?: any): {
|
|
4
|
+
GET: (url: string, data?: {}, options?: {}) => any;
|
|
5
|
+
DELETE: (url: string, data?: {}, options?: {}) => any;
|
|
6
|
+
POST: (url: string, data?: {}, options?: {}) => any;
|
|
7
|
+
PUT: (url: string, data?: {}, options?: {}) => any;
|
|
8
|
+
};
|