Compare commits
4 Commits
df34c1ad48
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d3dab30d48 | |||
| c7b62b0f4d | |||
| 8a67e20fc2 | |||
| 8d46ee78d3 |
@@ -352,7 +352,8 @@ $http.dataFactory = async function(res) {
|
||||
// 返回错误的结果(catch接受数据)
|
||||
return Promise.reject({
|
||||
statusCode: 0,
|
||||
errMsg: "【request】" + (httpData.info || httpData.msg),
|
||||
// errMsg: "【request】" + (httpData.info || httpData.msg),
|
||||
errMsg: (httpData.info || httpData.msg),
|
||||
data: res.data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
"src" : "图片路径"
|
||||
}
|
||||
],
|
||||
"versionName" : "1.0.61",
|
||||
"versionCode" : 1061,
|
||||
"versionName" : "1.0.66",
|
||||
"versionCode" : 1066,
|
||||
"app-plus" : {
|
||||
"nvueCompiler" : "weex",
|
||||
"compatible" : {
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "3.4.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.13",
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.15",
|
||||
"jquery": "^3.7.1",
|
||||
"tcplayer.js": "^5.1.0"
|
||||
},
|
||||
@@ -68,8 +68,8 @@
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"node_modules/edu-core": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#b5ece8b8abfeba98428f6e2191efae3312b5036f",
|
||||
"version": "1.0.15",
|
||||
"resolved": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#df2306c058445de44914622bf56459f76247f5b1",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/es5-shim": {
|
||||
@@ -393,8 +393,8 @@
|
||||
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
|
||||
},
|
||||
"edu-core": {
|
||||
"version": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#b5ece8b8abfeba98428f6e2191efae3312b5036f",
|
||||
"from": "edu-core@git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.13"
|
||||
"version": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#df2306c058445de44914622bf56459f76247f5b1",
|
||||
"from": "edu-core@git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.15"
|
||||
},
|
||||
"es5-shim": {
|
||||
"version": "4.6.7",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/dcloudio/hello-uniapp#readme",
|
||||
"dependencies": {
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.13",
|
||||
"edu-core": "git+https://git.nuttyreading.com/chenghuan/edu-core.git#v1.0.15",
|
||||
"jquery": "^3.7.1",
|
||||
"tcplayer.js": "^5.1.0"
|
||||
},
|
||||
|
||||
12
pages.json
12
pages.json
@@ -569,6 +569,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/medicaldes/medurl",
|
||||
"style": {
|
||||
"navigationBarTitleText": "详细介绍",
|
||||
"enablePullDownRefresh": false,
|
||||
"app-plus": {
|
||||
"bounce": "none",
|
||||
"titleNView": false,
|
||||
"popGesture": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/medicaldes/recordDetail",
|
||||
"style": {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
:course="{courseTitle:options.navTitle, chapterTitle: curriculumData.title, catalogueId: curriculumData.catalogueId || '', courseId: curriculumData.courseId || ''}"
|
||||
:cover="options.curriculumImgUrl || ''"
|
||||
:http="$http"
|
||||
:user-info="userInfo"
|
||||
/>
|
||||
|
||||
<view
|
||||
|
||||
@@ -702,9 +702,11 @@ export default {
|
||||
role = "心理学";
|
||||
} else if (type == 9) {
|
||||
role = "中西汇通学";
|
||||
} else if (type == 10) {
|
||||
role = "妇幼生殖";
|
||||
}
|
||||
this.goBuyTitle =
|
||||
"尊贵的" + role + "VIP,您的有效期到" + res.userVip.endTime;
|
||||
"尊贵的" + role + "VIP,您的有效期到" + res.userVip.endTime + '(不包含论坛)';
|
||||
this.goBuyType = 1;
|
||||
} else {
|
||||
//否则没有开通vip
|
||||
@@ -745,6 +747,8 @@ export default {
|
||||
text = "心理学";
|
||||
} else if (item == "9") {
|
||||
text = "中西汇通学";
|
||||
} else if (item == "10") {
|
||||
text = "妇幼生殖";
|
||||
}
|
||||
this.textList.push(text);
|
||||
});
|
||||
|
||||
@@ -356,11 +356,11 @@ export default {
|
||||
},
|
||||
onReady() {},
|
||||
onLoad() {
|
||||
if (plus.os.name == "Android") {
|
||||
this.isShowTaihu=true
|
||||
}else{
|
||||
this.isShowTaihu=false
|
||||
}
|
||||
if (plus.os.name == "Android") {
|
||||
this.isShowTaihu=true
|
||||
}else{
|
||||
this.isShowTaihu=false
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.getAdvertisement();
|
||||
});
|
||||
|
||||
@@ -63,12 +63,15 @@
|
||||
<uni-section
|
||||
class="mb-10"
|
||||
titleFontSize="18px"
|
||||
title="详细介绍"
|
||||
title="说明"
|
||||
type="line"
|
||||
v-if="prescriptDetail.content && prescriptDetail.content != ''"
|
||||
>
|
||||
<view class="item" v-html="prescriptDetail.content"> </view>
|
||||
</uni-section>
|
||||
<div class="detail-link-wrap" v-if="prescriptDetail.url && prescriptDetail.url != ''">
|
||||
<text class="detail-link" @click="openDetailUrl">详细介绍>></text>
|
||||
</div>
|
||||
|
||||
<!-- <uni-section class="mb-10" titleFontSize="18px" title="配伍" type="line">
|
||||
<view class="item" v-if="prescriptDetail.compatibility && prescriptDetail.compatibility != ''" v-html="prescriptDetail.compatibility">
|
||||
@@ -129,6 +132,13 @@ export default {
|
||||
},
|
||||
});
|
||||
},
|
||||
openDetailUrl() {
|
||||
uni.navigateTo({
|
||||
url:
|
||||
"/pages/medicaldes/medurl?url=" +
|
||||
encodeURIComponent(this.prescriptDetail.url),
|
||||
});
|
||||
},
|
||||
// 方剂详情
|
||||
getDetail() {
|
||||
$http
|
||||
@@ -207,6 +217,18 @@ export default {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.detail-link-wrap {
|
||||
padding: 10rpx 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.detail-link {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #007aff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-section-header__decoration.line {
|
||||
background-color: #18bc37;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,25 @@ export default {
|
||||
};
|
||||
},
|
||||
onLoad(e) {
|
||||
this.id = uni.getStorageSync("prescriptUrl");
|
||||
this.id = e.url ? decodeURIComponent(e.url) : uni.getStorageSync("prescriptUrl");
|
||||
// #ifdef APP-PLUS
|
||||
const pages = getCurrentPages()
|
||||
const page = pages[pages.length - 1];
|
||||
const currentWebview = page.$getAppWebview()
|
||||
currentWebview.setStyle({
|
||||
titleNView: {
|
||||
buttons: [{
|
||||
float: 'right',
|
||||
type: 'close',
|
||||
onclick: function() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}
|
||||
}]
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
|
||||
@@ -763,6 +763,9 @@ export default {
|
||||
} else if (item.type == "9") {
|
||||
item.text = "中西汇通学";
|
||||
this.textList.push(item.text);
|
||||
} else if (item.type == "10") {
|
||||
item.text = "妇幼生殖";
|
||||
this.textList.push(item.text);
|
||||
} else if (item.type == "1") {
|
||||
item.text = "医学S";
|
||||
} else if (item.type == "2") {
|
||||
|
||||
@@ -88,21 +88,21 @@
|
||||
>
|
||||
<text class="font_bold" style="display: block" v-else>VIP权限:</text>
|
||||
<view class="vip_qx_v" v-if="item.type == 1"
|
||||
>无限制观看吴门医述APP中医学、中西汇通学、针灸学、肿瘤学四个板块任意课程;</view
|
||||
>无限制观看吴门医述APP中医学、中西汇通学、针灸学、肿瘤学、妇幼生殖五个板块任意课程(不包含论坛);</view
|
||||
>
|
||||
<view class="vip_qx_v" v-else-if="item.type == 2"
|
||||
>无限制观看众妙之门APP与心灵空间APP任意课程;</view
|
||||
>无限制观看众妙之门APP与心灵空间APP任意课程(不包含论坛);</view
|
||||
>
|
||||
<view class="vip_qx_v" v-else-if="item.type == 7"
|
||||
>无限制观看众妙之门APP任意课程;</view
|
||||
>无限制观看众妙之门APP任意课程(不包含论坛);</view
|
||||
>
|
||||
<view class="vip_qx_v" v-else-if="item.type == 8"
|
||||
>无限制观看心灵空间APP任意课程;</view
|
||||
>无限制观看心灵空间APP任意课程(不包含论坛);</view
|
||||
>
|
||||
<view class="vip_qx_v" v-else
|
||||
>无限制观看吴门医述APP{{
|
||||
item.title.replace(/VIP/g, "")
|
||||
}}板块任意课程;</view
|
||||
}}板块任意课程(不包含论坛);</view
|
||||
>
|
||||
|
||||
<view class="vip_qx_v">
|
||||
|
||||
16
uni_modules/uni-usercapturescreen/changelog.md
Normal file
16
uni_modules/uni-usercapturescreen/changelog.md
Normal file
@@ -0,0 +1,16 @@
|
||||
## 1.0.7(2026-06-16)
|
||||
- 新增 iOS setUserCaptureScreen 支持 antiRecordOnly 参数:enable 为 false 且 antiRecordOnly 为 true 时,仅禁止录屏/投屏,允许截屏。实现方式为进入时提前挂载安全层(UITextField.isSecureTextEntry,默认不保护、保留 field 实例),通过 UIScreen.isCaptured 监听录屏/投屏,仅在录屏期间翻转 isSecureTextEntry——实时显示正常、录制到的文件为黑屏,平时不影响截屏(录屏进行中截屏也为黑)。Android/鸿蒙忽略该参数,仍为截屏+录屏一起禁止。
|
||||
## 1.0.6(2024-11-22)
|
||||
- 修复 HarmonyOS Next 上调用 setUserCaptureScreen 报错的 Bug
|
||||
## 1.0.5(2024-10-14)
|
||||
- 新增 支持 HarmonyOS Next 调用
|
||||
## 1.0.4(2023-03-24)
|
||||
新增开启/关闭防截屏功能
|
||||
## 1.0.3(2023-03-17)
|
||||
修复android平台 部分场景下js可能报错的问题
|
||||
## 1.0.2(2023-03-16)
|
||||
修复Android平台在小米设备无法监听的问题 修复Android平台调用uni.onUserCaptureScreen必然会触发回调的问题
|
||||
## 1.0.1(2022-10-27)
|
||||
修改插件描述
|
||||
## 1.0.0(2022-10-26)
|
||||
支持安卓、iOS、微信小程序平台
|
||||
163
uni_modules/uni-usercapturescreen/index.d.ts
vendored
Normal file
163
uni_modules/uni-usercapturescreen/index.d.ts
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
declare namespace UniNamespace {
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调参数
|
||||
*/
|
||||
type OnUserCaptureScreenCallbackResult = {
|
||||
/**
|
||||
* 截屏文件路径(仅Android返回)
|
||||
*/
|
||||
path ?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义
|
||||
*/
|
||||
type UserCaptureScreenCallback = (res : OnUserCaptureScreenCallbackResult) => void
|
||||
|
||||
type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
type OffUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调参数
|
||||
*/
|
||||
type SetUserCaptureScreenSuccess = {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenSuccessCallback = (res : SetUserCaptureScreenSuccess) => void
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* - 12001 "setUserCaptureScreen:system not support"
|
||||
* - 12010 "setUserCaptureScreen:system internal error"
|
||||
*/
|
||||
type SetUserCaptureScreenErrorCode = 12001 | 12010;
|
||||
|
||||
/**
|
||||
* SetUserCaptureScreen 的错误回调参数
|
||||
*/
|
||||
interface SetUserCaptureScreenFail {
|
||||
errCode : SetUserCaptureScreenErrorCode
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen失败回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenFailCallback = (res : SetUserCaptureScreenFail) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen完成回调函数定义
|
||||
*/
|
||||
type SetUserCaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen参数
|
||||
*/
|
||||
type SetUserCaptureScreenOptions = {
|
||||
/**
|
||||
* true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
enable : boolean;
|
||||
/**
|
||||
* 仅 iOS 生效。仅在 enable 为 false 时有意义:
|
||||
* true: 仅禁止录屏/投屏(录屏时画面被遮挡),允许截屏;
|
||||
* false/不传: 截屏与录屏一起禁止(默认行为)。
|
||||
*/
|
||||
antiRecordOnly ?: boolean;
|
||||
/**
|
||||
* 接口调用成功的回调函数
|
||||
*/
|
||||
// success : SetUserCaptureScreenSuccessCallback | null,
|
||||
success ?: SetUserCaptureScreenSuccessCallback,
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
// fail : SetUserCaptureScreenFailCallback | null,
|
||||
fail ?: SetUserCaptureScreenFailCallback,
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
// complete : SetUserCaptureScreenSuccessCallback | SetUserCaptureScreenFailCallback | null
|
||||
complete ?: SetUserCaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
type SetUserCaptureScreen = (options : SetUserCaptureScreenOptions) => void
|
||||
}
|
||||
|
||||
declare interface Uni {
|
||||
/**
|
||||
* 开启截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "9.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
onUserCaptureScreen(callback : UniNamespace.UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "9.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
offUserCaptureScreen(callback : UniNamespace.UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 设置防截屏
|
||||
*
|
||||
* @param {SetUserCaptureScreenOptions} options
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "13.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
*/
|
||||
setUserCaptureScreen(options : UniNamespace.SetUserCaptureScreenOptions) : void
|
||||
}
|
||||
97
uni_modules/uni-usercapturescreen/package.json
Normal file
97
uni_modules/uni-usercapturescreen/package.json
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"id": "uni-usercapturescreen",
|
||||
"displayName": "uni-usercapturescreen",
|
||||
"version": "1.0.7",
|
||||
"description": "用户主动截屏事件监听",
|
||||
"keywords": [
|
||||
"截屏"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.7.7"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"uni-ext-api":{
|
||||
"uni": {
|
||||
"onUserCaptureScreen": {
|
||||
"web": false
|
||||
},
|
||||
"offUserCaptureScreen": {
|
||||
"web": false
|
||||
},
|
||||
"setUserCaptureScreen": {
|
||||
"web": false,
|
||||
"mp-weixin": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": "y",
|
||||
"app-ios": "y",
|
||||
"app-harmony": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "n",
|
||||
"Android Browser": "n",
|
||||
"微信浏览器(Android)": "n",
|
||||
"QQ浏览器(Android)": "n"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "n",
|
||||
"IE": "n",
|
||||
"Edge": "n",
|
||||
"Firefox": "n",
|
||||
"Safari": "n"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "n",
|
||||
"百度": "n",
|
||||
"字节跳动": "n",
|
||||
"QQ": "n",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
uni_modules/uni-usercapturescreen/readme.md
Normal file
21
uni_modules/uni-usercapturescreen/readme.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# uni-usercapturescreen
|
||||
|
||||
用户主动截屏事件监听
|
||||
|
||||
### uni.onUserCaptureScreen
|
||||
|
||||
监听用户主动截屏事件,用户使用系统截屏按键截屏时触发此事件。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen)
|
||||
|
||||
### uni.offUserCaptureScreen
|
||||
|
||||
用户主动截屏事件。取消事件监听。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen)
|
||||
|
||||
### uni.setUserCaptureScreen
|
||||
|
||||
开启/关闭防截屏。
|
||||
|
||||
> 使用文档:[https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen)
|
||||
139
uni_modules/uni-usercapturescreen/utssdk/app-android/index.uts
Normal file
139
uni_modules/uni-usercapturescreen/utssdk/app-android/index.uts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { UTSAndroid } from "io.dcloud.uts";
|
||||
import ActivityCompat from "androidx.core.app.ActivityCompat";
|
||||
import Manifest from "android.Manifest";
|
||||
import PackageManager from "android.content.pm.PackageManager";
|
||||
import Build from "android.os.Build";
|
||||
import FileObserver from "android.os.FileObserver";
|
||||
import File from "java.io.File";
|
||||
import Environment from "android.os.Environment";
|
||||
import System from 'java.lang.System';
|
||||
import WindowManager from 'android.view.WindowManager';
|
||||
import { OnUserCaptureScreenCallbackResult, UserCaptureScreenCallback, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreenSuccess, SetUserCaptureScreenOptions, SetUserCaptureScreen } from "../interface.uts";
|
||||
import string from 'android.R.string';
|
||||
|
||||
|
||||
/**
|
||||
* 文件监听器
|
||||
*/
|
||||
let observer : ScreenFileObserver | null = null;
|
||||
/**
|
||||
* 记录文件监听器上次监听的时间戳,避免重复监听
|
||||
*/
|
||||
let lastObserverTime : number = 0;
|
||||
/**
|
||||
* 截屏回调
|
||||
*/
|
||||
let listener : UserCaptureScreenCallback | null = null;
|
||||
|
||||
/**
|
||||
* android 文件监听实现
|
||||
*/
|
||||
class ScreenFileObserver extends FileObserver {
|
||||
|
||||
/**
|
||||
* 截屏文件目录
|
||||
*/
|
||||
private screenFile : File;
|
||||
|
||||
constructor(screenFileStr : string) {
|
||||
super(screenFileStr);
|
||||
this.screenFile = new File(screenFileStr);
|
||||
}
|
||||
|
||||
override onEvent(event : Int, path : string | null) : void {
|
||||
// 只监听文件新增事件
|
||||
if (event == FileObserver.CREATE) {
|
||||
if (path != null) {
|
||||
const currentTime = System.currentTimeMillis();
|
||||
if ((currentTime - lastObserverTime) < 1000) {
|
||||
// 本地截屏行为比上一次超过1000ms, 才认为是一个有效的时间
|
||||
return;
|
||||
}
|
||||
lastObserverTime = currentTime;
|
||||
|
||||
const screenShotPath = new File(this.screenFile, path).getPath();
|
||||
const res : OnUserCaptureScreenCallbackResult = {
|
||||
path: screenShotPath
|
||||
}
|
||||
listener?.(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启截图监听
|
||||
*/
|
||||
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
// 检查相关权限是否已授予
|
||||
if (ActivityCompat.checkSelfPermission(UTSAndroid.getAppContext()!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
// 无权限,申请权限
|
||||
ActivityCompat.requestPermissions(UTSAndroid.getUniActivity()!, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1001);
|
||||
return;
|
||||
}
|
||||
// 更新监听
|
||||
listener = callback;
|
||||
|
||||
let directory_screenshot : File;
|
||||
if (Build.MANUFACTURER.toLowerCase() == "xiaomi") {
|
||||
// @Suppress("DEPRECATION")
|
||||
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM), "Screenshots");
|
||||
} else {
|
||||
// @Suppress("DEPRECATION")
|
||||
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES), "Screenshots");
|
||||
}
|
||||
// 先结束监听 再开启监听
|
||||
observer?.stopWatching();
|
||||
observer = new ScreenFileObserver(directory_screenshot.getPath());
|
||||
observer?.startWatching();
|
||||
|
||||
|
||||
UTSAndroid.onAppActivityDestroy(function(){
|
||||
observer?.stopWatching()
|
||||
observer = null
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*/
|
||||
export const offUserCaptureScreen : OffUserCaptureScreen = function (_ : UserCaptureScreenCallback | null) {
|
||||
// android10以上,关闭监听通过移除文件监听器实现
|
||||
observer?.stopWatching();
|
||||
observer = null;
|
||||
lastObserverTime = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否禁止截屏
|
||||
*/
|
||||
export const setUserCaptureScreen : SetUserCaptureScreen = function (option : SetUserCaptureScreenOptions) {
|
||||
// 切换到UI线程
|
||||
UTSAndroid.getUniActivity()?.runOnUiThread(new SetUserCaptureScreenRunnable(option.enable));
|
||||
const res : SetUserCaptureScreenSuccess = {}
|
||||
option.success?.(res);
|
||||
option.complete?.(res);
|
||||
}
|
||||
|
||||
class SetUserCaptureScreenRunnable extends Runnable {
|
||||
|
||||
/**
|
||||
* ture: 允许用户截屏
|
||||
* false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
private enable : boolean;
|
||||
|
||||
constructor(enable : boolean) {
|
||||
super();
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
override run() : void {
|
||||
if (this.enable) {
|
||||
UTSAndroid.getUniActivity()?.getWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
} else {
|
||||
UTSAndroid.getUniActivity()?.getWindow()?.addFlags(WindowManager.LayoutParams.FLAG_SECURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import { display } from '@kit.ArkUI';
|
||||
import { window } from '@kit.ArkUI';
|
||||
import { Callback, BusinessError } from '@kit.BasicServicesKit';
|
||||
|
||||
import { getAbilityContext } from '@dcloudio/uni-runtime';
|
||||
|
||||
import {
|
||||
OnUserCaptureScreen, UserCaptureScreenCallback,
|
||||
OffUserCaptureScreen,
|
||||
SetUserCaptureScreen, SetUserCaptureScreenOptions, SetUserCaptureScreenSuccess
|
||||
} from '../interface.uts';
|
||||
|
||||
const onUserCaptureScreenCallbacks: Function[] = []
|
||||
|
||||
const harmonyCaptureStatusChange: Callback<boolean> = (captureStatus: boolean) => {
|
||||
if (captureStatus) {
|
||||
onUserCaptureScreenCallbacks.forEach(cb => {
|
||||
typeof cb === 'function' && cb()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
display.on('captureStatusChange', harmonyCaptureStatusChange)
|
||||
|
||||
export const onUserCaptureScreen: OnUserCaptureScreen = function (callback: UserCaptureScreenCallback | null) {
|
||||
if (callback) {
|
||||
onUserCaptureScreenCallbacks.push(callback)
|
||||
}
|
||||
}
|
||||
|
||||
export const offUserCaptureScreen: OffUserCaptureScreen = function (callback: UserCaptureScreenCallback | null) {
|
||||
if (callback) {
|
||||
const index = onUserCaptureScreenCallbacks.indexOf(callback)
|
||||
if (index > -1) {
|
||||
onUserCaptureScreenCallbacks.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const setUserCaptureScreen: SetUserCaptureScreen = function (options: SetUserCaptureScreenOptions) {
|
||||
const errSubject = 'uni-usercapturescreen'
|
||||
const setUserCaptureScreenSuccess: SetUserCaptureScreenSuccess = {}
|
||||
window.getLastWindow(getAbilityContext()!, (err, window) => {
|
||||
const errCode: number = err.code;
|
||||
if (errCode) {
|
||||
options.fail?.({
|
||||
errCode: (err as BusinessError).code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${(err as BusinessError).message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
UTSHarmony.requestSystemPermission(['ohos.permission.PRIVACY_WINDOW'], (allRight: boolean, _grantedList: string[]) => {
|
||||
if (allRight) {
|
||||
window.setWindowPrivacyMode(!options.enable, (err: BusinessError) => {
|
||||
const errCode: number = err.code;
|
||||
if (errCode) {
|
||||
options.fail?.({
|
||||
errCode: err.code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${err.message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
return;
|
||||
}
|
||||
options.success?.(setUserCaptureScreenSuccess);
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
});
|
||||
} else {
|
||||
throw new Error('permission denied')
|
||||
}
|
||||
}, (_doNotAskAgain: boolean, _grantedList: string[]) => {
|
||||
throw new Error('permission denied');
|
||||
})
|
||||
} catch (err) {
|
||||
options.fail?.({
|
||||
errCode: (err as BusinessError).code,
|
||||
errSubject,
|
||||
errMsg: `setUserCaptureScreen:fail ${(err as BusinessError).message}`
|
||||
} as IUniError)
|
||||
options.complete?.(setUserCaptureScreenSuccess);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
324
uni_modules/uni-usercapturescreen/utssdk/app-ios/index.uts
Normal file
324
uni_modules/uni-usercapturescreen/utssdk/app-ios/index.uts
Normal file
@@ -0,0 +1,324 @@
|
||||
import { NotificationCenter } from 'Foundation';
|
||||
import { CGRect } from "CoreFoundation";
|
||||
import { UIApplication, UIView, UITextField, UIScreen, UIDevice } from "UIKit"
|
||||
import { UTSiOS } from "DCloudUTSFoundation"
|
||||
import { DispatchQueue } from 'Dispatch';
|
||||
import { SetUserCaptureScreenOptions, OnUserCaptureScreenCallbackResult, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen, UserCaptureScreenCallback, SetUserCaptureScreenSuccess } from "../interface.uts"
|
||||
import { SetUserCaptureScreenFailImpl } from "../unierror.uts"
|
||||
/**
|
||||
* 定义监听截屏事件工具类
|
||||
*/
|
||||
class CaptureScreenTool {
|
||||
static listener : UserCaptureScreenCallback | null;
|
||||
static secureView : UIView | null;
|
||||
|
||||
// ===== 仅防录屏(动态切换)相关状态 =====
|
||||
// 保留 UITextField,使 isSecureTextEntry 可在录屏开始/结束时反复切换
|
||||
static secureField : UITextField | null;
|
||||
// field 的安全画布(已挂入视图层级,承载 App 根视图)
|
||||
static secureCanvas : UIView | null;
|
||||
// 被安全画布包裹的 App 根视图(用于卸载时还原)
|
||||
static secureRootView : UIView | null;
|
||||
// 是否已为"仅防录屏"挂载安全层
|
||||
static recordWrapped : boolean = false;
|
||||
|
||||
// 监听截屏
|
||||
static listenCaptureScreen(callback : UserCaptureScreenCallback | null) {
|
||||
this.listener = callback
|
||||
|
||||
// 注册监听截屏事件及回调方法
|
||||
// target-action 回调方法需要通过 Selector("方法名") 构建
|
||||
const method = Selector("userDidTakeScreenshot")
|
||||
NotificationCenter.default.addObserver(this, selector = method, name = UIApplication.userDidTakeScreenshotNotification, object = null)
|
||||
}
|
||||
|
||||
// 捕获截屏回调的方法
|
||||
// target-action 的方法前需要添加 @objc 前缀
|
||||
@objc static userDidTakeScreenshot() {
|
||||
// 回调
|
||||
const res: OnUserCaptureScreenCallbackResult = {
|
||||
}
|
||||
this.listener?.(res)
|
||||
}
|
||||
|
||||
// 移除监听事件
|
||||
static removeListen(callback : UserCaptureScreenCallback | null) {
|
||||
this.listener = null
|
||||
NotificationCenter.default.removeObserver(this)
|
||||
}
|
||||
|
||||
static createSecureView() : UIView | null {
|
||||
let field = new UITextField(frame = CGRect.zero)
|
||||
field.isSecureTextEntry = true
|
||||
if (field.subviews.length > 0 && UIDevice.current.systemVersion != '15.1') {
|
||||
let view = field.subviews[0]
|
||||
view.subviews.forEach((item) => {
|
||||
item.removeFromSuperview()
|
||||
})
|
||||
view.isUserInteractionEnabled = true
|
||||
return view
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 应用防截屏遮罩(secureView:实时显示正常,但被截屏/录屏捕获到的内容为黑屏)
|
||||
// 不触发回调,供内部复用;注意:需在主线程调用
|
||||
static applySecureViewInternal() {
|
||||
if (this.secureView != null) {
|
||||
// 已应用,避免重复包裹
|
||||
return
|
||||
}
|
||||
let secureView = this.createSecureView()
|
||||
let window = UTSiOS.getKeyWindow()
|
||||
let rootView = window.rootViewController == null ? null : window.rootViewController!.view
|
||||
if (secureView != null && rootView != null) {
|
||||
let rootSuperview = rootView!.superview
|
||||
if (rootSuperview != null) {
|
||||
this.secureView = secureView
|
||||
rootSuperview!.addSubview(secureView!)
|
||||
rootView!.removeFromSuperview()
|
||||
secureView!.addSubview(rootView!)
|
||||
// secureView 充满父视图并随父视图宽高自适应(横竖屏、全屏切换时自动跟随)
|
||||
secureView!.frame = rootSuperview!.bounds
|
||||
secureView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
// rootView 充满 secureView 并自适应,避免全屏时被固定在竖屏尺寸而缩到角落
|
||||
rootView!.frame = secureView!.bounds
|
||||
rootView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 开启防截屏
|
||||
static onAntiScreenshot(option : SetUserCaptureScreenOptions) {
|
||||
// uts方法默认会在子线程中执行,涉及 UI 操作必须在主线程中运行,通过 DispatchQueue.main.async 方法可将代码在主线程中运行
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
this.applySecureViewInternal()
|
||||
let res: SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
option.success?.(res)
|
||||
option.complete?.(res)
|
||||
})
|
||||
}
|
||||
|
||||
// ===== 仅防录屏:提前挂载安全层 + 翻转 isSecureTextEntry =====
|
||||
|
||||
// 提前挂载安全层(应在录屏开始前调用,例如进入页面时)。
|
||||
// 挂载后默认不保护(isSecureTextEntry = false)→ 截屏正常、实时正常。
|
||||
// 注意:需在主线程调用。
|
||||
static setupRecordSecureWrapper() {
|
||||
if (this.recordWrapped) {
|
||||
return
|
||||
}
|
||||
let field = new UITextField(frame = CGRect.zero)
|
||||
field.isSecureTextEntry = true
|
||||
// 15.1 系统 secureView 不可用;拿不到安全画布则放弃
|
||||
if (field.subviews.length == 0 || UIDevice.current.systemVersion == '15.1') {
|
||||
return
|
||||
}
|
||||
let canvas = field.subviews[0]
|
||||
canvas.subviews.forEach((item) => {
|
||||
item.removeFromSuperview()
|
||||
})
|
||||
canvas.isUserInteractionEnabled = true
|
||||
|
||||
let window = UTSiOS.getKeyWindow()
|
||||
let rootView = window.rootViewController == null ? null : window.rootViewController!.view
|
||||
if (rootView == null) {
|
||||
return
|
||||
}
|
||||
let rootSuperview = rootView!.superview
|
||||
if (rootSuperview == null) {
|
||||
return
|
||||
}
|
||||
|
||||
// 把安全画布插入原层级,并把 App 根视图移入画布
|
||||
rootSuperview!.addSubview(canvas)
|
||||
rootView!.removeFromSuperview()
|
||||
canvas.addSubview(rootView!)
|
||||
canvas.frame = rootSuperview!.bounds
|
||||
canvas.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
rootView!.frame = canvas.bounds
|
||||
rootView!.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
|
||||
|
||||
// 关键:保留 field,后续才能切换 isSecureTextEntry
|
||||
this.secureField = field
|
||||
this.secureCanvas = canvas
|
||||
this.secureRootView = rootView
|
||||
this.recordWrapped = true
|
||||
|
||||
// 默认不保护:允许截屏、实时正常
|
||||
field.isSecureTextEntry = false
|
||||
}
|
||||
|
||||
// 切换录屏保护:true=保护(录屏文件黑、实时正常、此刻截屏也黑);false=不保护(允许截屏)
|
||||
// 注意:需在主线程调用。
|
||||
static setRecordSecure(secure : boolean) {
|
||||
if (this.secureField != null) {
|
||||
this.secureField!.isSecureTextEntry = secure
|
||||
}
|
||||
}
|
||||
|
||||
// 卸载安全层,恢复原始视图层级。注意:需在主线程调用。
|
||||
static teardownRecordSecureWrapper() {
|
||||
if (!this.recordWrapped) {
|
||||
return
|
||||
}
|
||||
if (this.secureField != null) {
|
||||
this.secureField!.isSecureTextEntry = false
|
||||
}
|
||||
if (this.secureCanvas != null && this.secureRootView != null) {
|
||||
let rootSuperview = this.secureCanvas!.superview
|
||||
if (rootSuperview != null) {
|
||||
rootSuperview!.addSubview(this.secureRootView!)
|
||||
this.secureRootView!.frame = rootSuperview!.bounds
|
||||
this.secureCanvas!.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
this.secureField = null
|
||||
this.secureCanvas = null
|
||||
this.secureRootView = null
|
||||
this.recordWrapped = false
|
||||
}
|
||||
|
||||
// 移除防截屏遮罩视图(不触发回调,供内部复用)
|
||||
// 注意:需在主线程调用
|
||||
static removeSecureViewInternal() {
|
||||
if (this.secureView != null) {
|
||||
let window = UTSiOS.getKeyWindow()
|
||||
let rootView = window.rootViewController == null ? null : window.rootViewController!.view
|
||||
if (rootView != null && this.secureView!.superview != null) {
|
||||
let rootSuperview = this.secureView!.superview
|
||||
if (rootSuperview != null) {
|
||||
rootSuperview!.addSubview(rootView!)
|
||||
this.secureView!.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
this.secureView = null
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭防截屏
|
||||
static offAntiScreenshot(option : SetUserCaptureScreenOptions) {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
this.removeSecureViewInternal()
|
||||
let res: SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
option.success?.(res)
|
||||
option.complete?.(res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 防录屏工具类:基于 UIScreen.isCaptured 监听录屏/投屏状态,动态切换安全层。
|
||||
* 截屏不会触发 isCaptured,因此可做到"允许截屏、仅在录屏时保护"。
|
||||
*
|
||||
* 实现要点(避免实时画面变黑):
|
||||
* 1) 进入时(录屏开始前)就提前挂好安全层,且默认不保护 → 截屏正常、实时正常;
|
||||
* 2) 仅在录屏期间翻转 isSecureTextEntry = true → 录屏文件黑、实时正常、此刻截屏也黑;
|
||||
* 3) 录屏结束翻回 false → 截屏恢复正常。
|
||||
*/
|
||||
class ScreenRecordTool {
|
||||
// 是否已注册监听
|
||||
static monitoring : boolean = false;
|
||||
|
||||
// 开启防录屏:提前挂载安全层并监听录屏状态变化
|
||||
static onAntiScreenRecord() {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
// 关键:录屏开始前就把安全层挂好(默认不保护)
|
||||
CaptureScreenTool.setupRecordSecureWrapper()
|
||||
if (!this.monitoring) {
|
||||
this.monitoring = true
|
||||
const method = Selector("screenCaptureDidChange")
|
||||
NotificationCenter.default.addObserver(this, selector = method, name = UIScreen.capturedDidChangeNotification, object = null)
|
||||
}
|
||||
// 进入时若已经在录屏,立即按当前状态保护
|
||||
this.applyIfNeeded()
|
||||
})
|
||||
}
|
||||
|
||||
// 录屏状态变化回调
|
||||
@objc static screenCaptureDidChange() {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
this.applyIfNeeded()
|
||||
})
|
||||
}
|
||||
|
||||
// 根据当前录屏状态翻转安全层开关
|
||||
static applyIfNeeded() {
|
||||
CaptureScreenTool.setRecordSecure(UIScreen.main.isCaptured)
|
||||
}
|
||||
|
||||
// 关闭防录屏:移除监听并卸载安全层
|
||||
static offAntiScreenRecord() {
|
||||
DispatchQueue.main.async(execute = () : void => {
|
||||
if (this.monitoring) {
|
||||
NotificationCenter.default.removeObserver(this, name = UIScreen.capturedDidChangeNotification, object = null)
|
||||
this.monitoring = false
|
||||
}
|
||||
CaptureScreenTool.teardownRecordSecureWrapper()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启截图监听
|
||||
*/
|
||||
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
CaptureScreenTool.listenCaptureScreen(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*/
|
||||
export const offUserCaptureScreen : OffUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
|
||||
CaptureScreenTool.removeListen(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启/关闭防截屏
|
||||
*/
|
||||
export const setUserCaptureScreen : SetUserCaptureScreen = function (options : SetUserCaptureScreenOptions) {
|
||||
const systemVersion = UIDevice.current.systemVersion
|
||||
|
||||
if (options.enable == true) {
|
||||
// 允许截屏与录屏:无条件清理录屏遮罩,再移除防截屏遮罩。
|
||||
// 清理动作不受版本限制,避免遗留监听/遮罩。
|
||||
ScreenRecordTool.offAntiScreenRecord()
|
||||
CaptureScreenTool.offAntiScreenshot(options)
|
||||
return
|
||||
}
|
||||
|
||||
if (options.antiRecordOnly == true) {
|
||||
// 仅禁止录屏、允许截屏:进入页面时提前挂好安全层(默认不保护),
|
||||
// 用 UIScreen.isCaptured(iOS 11+)监听录屏/投屏,仅在录屏期间翻转 isSecureTextEntry
|
||||
// —— 实时显示正常、录到的画面为黑屏,且平时不影响截屏。
|
||||
// 注意:secureView 在 iOS 15.1 上不可用,该版本录屏保护会失效(属系统已知问题)。
|
||||
if (systemVersion < "11.0") {
|
||||
let res = new SetUserCaptureScreenFailImpl(12001)
|
||||
options.fail?.(res)
|
||||
options.complete?.(res)
|
||||
return
|
||||
}
|
||||
ScreenRecordTool.onAntiScreenRecord()
|
||||
let res: SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
options.success?.(res)
|
||||
options.complete?.(res)
|
||||
return
|
||||
}
|
||||
|
||||
// 默认:截屏与录屏一起禁止(secureView 方案,受系统版本限制)
|
||||
if (systemVersion < "13.0") {
|
||||
let res = new SetUserCaptureScreenFailImpl(12001)
|
||||
options.fail?.(res)
|
||||
options.complete?.(res)
|
||||
} else if (systemVersion == "15.1") {
|
||||
let res = new SetUserCaptureScreenFailImpl(12010)
|
||||
options.fail?.(res)
|
||||
options.complete?.(res)
|
||||
} else {
|
||||
CaptureScreenTool.onAntiScreenshot(options)
|
||||
}
|
||||
}
|
||||
|
||||
176
uni_modules/uni-usercapturescreen/utssdk/interface.uts
Normal file
176
uni_modules/uni-usercapturescreen/utssdk/interface.uts
Normal file
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调参数
|
||||
*/
|
||||
export type OnUserCaptureScreenCallbackResult = {
|
||||
/**
|
||||
* 截屏文件路径(仅Android返回)
|
||||
*/
|
||||
path ?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.onUserCaptureScreen/uni.offUserCaptureScreen回调函数定义
|
||||
*/
|
||||
export type UserCaptureScreenCallback = (res : OnUserCaptureScreenCallbackResult) => void
|
||||
|
||||
export type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
export type OffUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调参数
|
||||
*/
|
||||
export type SetUserCaptureScreenSuccess = {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen成功回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenSuccessCallback = (res : SetUserCaptureScreenSuccess) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen失败回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenFailCallback = (res : IUniError) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen完成回调函数定义
|
||||
*/
|
||||
export type SetUserCaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
/**
|
||||
* uni.setUserCaptureScreen参数
|
||||
*/
|
||||
|
||||
export type SetUserCaptureScreenOptions = {
|
||||
/**
|
||||
* true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容
|
||||
*/
|
||||
enable : boolean;
|
||||
/**
|
||||
* 仅 iOS 生效。仅在 enable 为 false 时有意义:
|
||||
* true: 仅禁止录屏/投屏(录屏时画面被遮挡),允许截屏;
|
||||
* false/不传: 截屏与录屏一起禁止(默认行为)。
|
||||
*/
|
||||
antiRecordOnly ?: boolean;
|
||||
/**
|
||||
* 接口调用成功的回调函数
|
||||
*/
|
||||
// success : SetUserCaptureScreenSuccessCallback | null,
|
||||
success ?: SetUserCaptureScreenSuccessCallback,
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
// fail : SetUserCaptureScreenFailCallback | null,
|
||||
fail ?: SetUserCaptureScreenFailCallback,
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
// complete : SetUserCaptureScreenSuccessCallback | SetUserCaptureScreenFailCallback | null
|
||||
complete ?: SetUserCaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
* - 12001 "setUserCaptureScreen:system not support"
|
||||
* - 12010 "setUserCaptureScreen:system internal error"
|
||||
*/
|
||||
export type SetUserCaptureScreenErrorCode = 12001 | 12010;
|
||||
/**
|
||||
* SetUserCaptureScreen 的错误回调参数
|
||||
*/
|
||||
export interface SetUserCaptureScreenFail extends IUniError {
|
||||
errCode : SetUserCaptureScreenErrorCode
|
||||
};
|
||||
|
||||
export type SetUserCaptureScreen = (options : SetUserCaptureScreenOptions) => void
|
||||
|
||||
export interface Uni {
|
||||
/**
|
||||
* 开启截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "12.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
onUserCaptureScreen(callback : UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 关闭截屏监听
|
||||
*
|
||||
* @param {UserCaptureScreenCallback} callback
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "12.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",,
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
* @autotest { expectCallback: true }
|
||||
*/
|
||||
offUserCaptureScreen(callback : UserCaptureScreenCallback | null) : void,
|
||||
/**
|
||||
* 设置防截屏
|
||||
*
|
||||
* @param {SetUserCaptureScreenOptions} options
|
||||
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "4.4.4",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* },
|
||||
* "ios": {
|
||||
* "osVer": "13.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "4.11"
|
||||
* },
|
||||
* "harmony": {
|
||||
* "osVer": "3.0",
|
||||
* "uniVer": "4.25",
|
||||
* "unixVer": "x"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3 //支持的vue版本
|
||||
*/
|
||||
setUserCaptureScreen(options : SetUserCaptureScreenOptions) : void
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export function onUserCaptureScreen (callback) {
|
||||
return wx.onUserCaptureScreen(callback)
|
||||
}
|
||||
|
||||
export function offUserCaptureScreen (callback) {
|
||||
return wx.offUserCaptureScreen(callback)
|
||||
}
|
||||
35
uni_modules/uni-usercapturescreen/utssdk/unierror.uts
Normal file
35
uni_modules/uni-usercapturescreen/utssdk/unierror.uts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { SetUserCaptureScreenErrorCode, SetUserCaptureScreenFail } from "./interface.uts"
|
||||
/**
|
||||
* 错误主题
|
||||
*/
|
||||
export const UniErrorSubject = 'uni-usercapturescreen';
|
||||
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @UniError
|
||||
*/
|
||||
export const UniErrors : Map<SetUserCaptureScreenErrorCode, string> = new Map([
|
||||
/**
|
||||
* 错误码及对应的错误信息
|
||||
*/
|
||||
[12001, 'setUserCaptureScreen:system not support'],
|
||||
[12010, 'setUserCaptureScreen:system internal error'],
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* 错误对象实现
|
||||
*/
|
||||
export class SetUserCaptureScreenFailImpl extends UniError implements SetUserCaptureScreenFail {
|
||||
|
||||
/**
|
||||
* 错误对象构造函数
|
||||
*/
|
||||
constructor(errCode : SetUserCaptureScreenErrorCode) {
|
||||
super();
|
||||
this.errSubject = UniErrorSubject;
|
||||
this.errCode = errCode;
|
||||
this.errMsg = UniErrors[errCode] ?? "";
|
||||
}
|
||||
}
|
||||
29
uni_modules/yb-screen-capture/index.d.ts
vendored
Normal file
29
uni_modules/yb-screen-capture/index.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
export type CaptureScreenSuccess = {
|
||||
/**
|
||||
* 截图结果,格式为 data URL:data:image/jpeg;base64,xxxx
|
||||
*/
|
||||
base64 : string
|
||||
}
|
||||
|
||||
export type CaptureScreenSuccessCallback = (res : CaptureScreenSuccess) => void
|
||||
|
||||
export type CaptureScreenFail = {
|
||||
errCode : number,
|
||||
errMsg : string
|
||||
}
|
||||
|
||||
export type CaptureScreenFailCallback = (res : CaptureScreenFail) => void
|
||||
|
||||
export type CaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
export type CaptureScreenOptions = {
|
||||
success ?: CaptureScreenSuccessCallback,
|
||||
fail ?: CaptureScreenFailCallback,
|
||||
complete ?: CaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取当前应用窗口画面(含视频等硬件加速渲染内容),通过 base64 返回。
|
||||
* 仅 App-Android 生效,基于 Android PixelCopy 实现。
|
||||
*/
|
||||
export declare const captureScreen : (options : CaptureScreenOptions) => void
|
||||
85
uni_modules/yb-screen-capture/package.json
Normal file
85
uni_modules/yb-screen-capture/package.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"id": "yb-screen-capture",
|
||||
"displayName": "yb-screen-capture",
|
||||
"version": "1.0.0",
|
||||
"description": "截取当前应用窗口(含硬件加速渲染的视频画面),返回 base64",
|
||||
"keywords": [
|
||||
"截图",
|
||||
"截屏",
|
||||
"PixelCopy"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.7.7"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": "y",
|
||||
"app-ios": "n",
|
||||
"app-harmony": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "n",
|
||||
"Android Browser": "n",
|
||||
"微信浏览器(Android)": "n",
|
||||
"QQ浏览器(Android)": "n"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "n",
|
||||
"IE": "n",
|
||||
"Edge": "n",
|
||||
"Firefox": "n",
|
||||
"Safari": "n"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "n",
|
||||
"阿里": "n",
|
||||
"百度": "n",
|
||||
"字节跳动": "n",
|
||||
"QQ": "n",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
uni_modules/yb-screen-capture/readme.md
Normal file
22
uni_modules/yb-screen-capture/readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# yb-screen-capture
|
||||
|
||||
截取当前应用窗口画面(含视频等硬件加速渲染内容),通过 base64 返回。
|
||||
|
||||
- 仅 **App-Android** 生效,基于 Android `PixelCopy` 实现(Android 8.0 及以上能正确截取视频画面;低于 8.0 降级为 View 截图,视频区域可能为黑屏)。
|
||||
- 截图范围为「当前屏幕可见区域」,不是长页面截图。
|
||||
|
||||
## 使用
|
||||
|
||||
```js
|
||||
uni.captureScreen({
|
||||
success: (res) => {
|
||||
// res.base64 形如:data:image/jpeg;base64,xxxx
|
||||
console.log(res.base64)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(err.errCode, err.errMsg)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
> 注意:UTS 插件需要打自定义基座(标准基座无法运行)才能调试/运行。
|
||||
127
uni_modules/yb-screen-capture/utssdk/app-android/index.uts
Normal file
127
uni_modules/yb-screen-capture/utssdk/app-android/index.uts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { UTSAndroid } from "io.dcloud.uts";
|
||||
import PixelCopy from "android.view.PixelCopy";
|
||||
import OnPixelCopyFinishedListener from "android.view.PixelCopy.OnPixelCopyFinishedListener";
|
||||
import Bitmap from "android.graphics.Bitmap";
|
||||
import Canvas from "android.graphics.Canvas";
|
||||
import Handler from "android.os.Handler";
|
||||
import Looper from "android.os.Looper";
|
||||
import Build from "android.os.Build";
|
||||
import ByteArrayOutputStream from "java.io.ByteArrayOutputStream";
|
||||
import Base64 from "android.util.Base64";
|
||||
import {
|
||||
CaptureScreen,
|
||||
CaptureScreenOptions,
|
||||
CaptureScreenSuccess,
|
||||
CaptureScreenFail
|
||||
} from "../interface.uts";
|
||||
|
||||
/**
|
||||
* 将 Bitmap 压缩为 JPEG 并编码为 data URL 形式的 base64
|
||||
*/
|
||||
function encodeBitmapToBase64(bitmap : Bitmap) : string {
|
||||
const baos = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
|
||||
const bytes = baos.toByteArray();
|
||||
const base64 = Base64.encodeToString(bytes, Base64.NO_WRAP);
|
||||
bitmap.recycle();
|
||||
return "data:image/jpeg;base64," + base64;
|
||||
}
|
||||
|
||||
/**
|
||||
* PixelCopy 完成监听器
|
||||
*/
|
||||
class PixelCopyListener extends OnPixelCopyFinishedListener {
|
||||
|
||||
private bitmap : Bitmap;
|
||||
private options : CaptureScreenOptions;
|
||||
|
||||
constructor(bitmap : Bitmap, options : CaptureScreenOptions) {
|
||||
super();
|
||||
this.bitmap = bitmap;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
override onPixelCopyFinished(copyResult : Int) : void {
|
||||
if (copyResult == PixelCopy.SUCCESS) {
|
||||
const base64 = encodeBitmapToBase64(this.bitmap);
|
||||
const res : CaptureScreenSuccess = { base64: base64 };
|
||||
this.options.success?.(res);
|
||||
this.options.complete?.(res);
|
||||
} else {
|
||||
this.bitmap.recycle();
|
||||
const res : CaptureScreenFail = {
|
||||
errCode: 12010,
|
||||
errMsg: "captureScreen:fail PixelCopy copyResult=" + copyResult
|
||||
};
|
||||
this.options.fail?.(res);
|
||||
this.options.complete?.(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在 UI 线程执行实际截图
|
||||
*/
|
||||
class CaptureRunnable extends Runnable {
|
||||
|
||||
private options : CaptureScreenOptions;
|
||||
|
||||
constructor(options : CaptureScreenOptions) {
|
||||
super();
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
override run() : void {
|
||||
try {
|
||||
const activity = UTSAndroid.getUniActivity();
|
||||
if (activity == null) {
|
||||
const res : CaptureScreenFail = { errCode: 12010, errMsg: "captureScreen:fail activity is null" };
|
||||
this.options.fail?.(res);
|
||||
this.options.complete?.(res);
|
||||
return;
|
||||
}
|
||||
// 注意:UTS 中 getWindow() 返回可空类型,必须用 ! 断言,否则编译失败
|
||||
const window = activity!.getWindow()!;
|
||||
const decorView = window.getDecorView()!;
|
||||
const width = decorView.getWidth();
|
||||
const height = decorView.getHeight();
|
||||
if (width <= 0 || height <= 0) {
|
||||
const res : CaptureScreenFail = { errCode: 12010, errMsg: "captureScreen:fail invalid window size" };
|
||||
this.options.fail?.(res);
|
||||
this.options.complete?.(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
// Android 8.0+:使用 PixelCopy 可以正确截取 SurfaceView/视频等硬件加速画面
|
||||
const handler = new Handler(Looper.getMainLooper());
|
||||
PixelCopy.request(window, bitmap, new PixelCopyListener(bitmap, this.options), handler);
|
||||
} else {
|
||||
// 低版本降级:仅能截取 View 层级内容,视频区域可能为黑屏
|
||||
const canvas = new Canvas(bitmap);
|
||||
decorView.draw(canvas);
|
||||
const base64 = encodeBitmapToBase64(bitmap);
|
||||
const res : CaptureScreenSuccess = { base64: base64 };
|
||||
this.options.success?.(res);
|
||||
this.options.complete?.(res);
|
||||
}
|
||||
} catch (e) {
|
||||
const res : CaptureScreenFail = { errCode: 12010, errMsg: "captureScreen:fail " + e.toString() };
|
||||
this.options.fail?.(res);
|
||||
this.options.complete?.(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const captureScreen : CaptureScreen = function (options : CaptureScreenOptions) {
|
||||
const activity = UTSAndroid.getUniActivity();
|
||||
if (activity == null) {
|
||||
const res : CaptureScreenFail = { errCode: 12010, errMsg: "captureScreen:fail activity is null" };
|
||||
options.fail?.(res);
|
||||
options.complete?.(res);
|
||||
return;
|
||||
}
|
||||
activity!.runOnUiThread(new CaptureRunnable(options));
|
||||
}
|
||||
73
uni_modules/yb-screen-capture/utssdk/interface.uts
Normal file
73
uni_modules/yb-screen-capture/utssdk/interface.uts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* uni.captureScreen 成功回调参数
|
||||
*/
|
||||
export type CaptureScreenSuccess = {
|
||||
/**
|
||||
* 截图结果,格式为 data URL:data:image/jpeg;base64,xxxx
|
||||
*/
|
||||
base64 : string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.captureScreen 成功回调函数定义
|
||||
*/
|
||||
export type CaptureScreenSuccessCallback = (res : CaptureScreenSuccess) => void
|
||||
|
||||
/**
|
||||
* uni.captureScreen 失败回调参数
|
||||
*/
|
||||
export type CaptureScreenFail = {
|
||||
errCode : number,
|
||||
errMsg : string
|
||||
}
|
||||
|
||||
/**
|
||||
* uni.captureScreen 失败回调函数定义
|
||||
*/
|
||||
export type CaptureScreenFailCallback = (res : CaptureScreenFail) => void
|
||||
|
||||
/**
|
||||
* uni.captureScreen 完成回调函数定义(成功、失败都会执行)
|
||||
*/
|
||||
export type CaptureScreenCompleteCallback = (res : any) => void
|
||||
|
||||
/**
|
||||
* uni.captureScreen 参数
|
||||
*/
|
||||
export type CaptureScreenOptions = {
|
||||
/**
|
||||
* 接口调用成功的回调函数
|
||||
*/
|
||||
success ?: CaptureScreenSuccessCallback,
|
||||
/**
|
||||
* 接口调用失败的回调函数
|
||||
*/
|
||||
fail ?: CaptureScreenFailCallback,
|
||||
/**
|
||||
* 接口调用结束的回调函数(调用成功、失败都会执行)
|
||||
*/
|
||||
complete ?: CaptureScreenCompleteCallback
|
||||
}
|
||||
|
||||
export type CaptureScreen = (options : CaptureScreenOptions) => void
|
||||
|
||||
export interface Uni {
|
||||
/**
|
||||
* 截取当前应用窗口画面(含视频等硬件加速渲染内容),通过 base64 返回。
|
||||
* 仅 App-Android 生效,基于 Android PixelCopy 实现。
|
||||
*
|
||||
* @param {CaptureScreenOptions} options
|
||||
* @uniPlatform {
|
||||
* "app": {
|
||||
* "android": {
|
||||
* "osVer": "8.0",
|
||||
* "uniVer": "3.7.7",
|
||||
* "unixVer": "3.9.0"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @uniVersion 3.7.7
|
||||
* @uniVueVersion 2,3
|
||||
*/
|
||||
captureScreen(options : CaptureScreenOptions) : void
|
||||
}
|
||||
Reference in New Issue
Block a user