提交 bbec54cb 编写于 作者: DCloud_iOS_XHY's avatar DCloud_iOS_XHY

Merge branch 'dev' of gitcode.net:dcloud/uni-api into dev

...@@ -28,7 +28,8 @@ ...@@ -28,7 +28,8 @@
title: 'Hello', title: 'Hello',
memListener:null, memListener:null,
setUserCaptureScreenFlag: false, setUserCaptureScreenFlag: false,
setUserCaptureScreenText: '禁止截屏' setUserCaptureScreenText: '禁止截屏',
permissionGranted: false
} }
}, },
onLoad() { onLoad() {
...@@ -142,13 +143,9 @@ ...@@ -142,13 +143,9 @@
// 除android 之外的平台,不需要判断返回状态码 // 除android 之外的平台,不需要判断返回状态码
if(res.errCode == -1){ if(res.errCode == -1){
// 启动失败 // 启动失败
that.permissionGranted = true;
return ; return ;
}else if(res.errCode == 0){ }else if(res.errCode == 0){
uni.showToast({
icon:"none",
title:'截屏监听已开启'
})
}else {
uni.showToast({ uni.showToast({
icon:"none", icon:"none",
title:'捕获截屏事件' title:'捕获截屏事件'
...@@ -164,7 +161,7 @@ ...@@ -164,7 +161,7 @@
} }
}); });
if (uni.getSystemInfoSync().platform != "android") { if (uni.getSystemInfoSync().platform != "android" || that.permissionGranted) {
// 除android 之外的平台,直接提示监听已开启 // 除android 之外的平台,直接提示监听已开启
uni.showToast({ uni.showToast({
icon:"none", icon:"none",
...@@ -198,13 +195,13 @@ ...@@ -198,13 +195,13 @@
uni.setUserCaptureScreen({ uni.setUserCaptureScreen({
enable: flag, enable: flag,
success: (res) => { success: (res) => {
console.log("setUserCaptureScreen open: " + flag + " success: " + JSON.stringify(res)); console.log("setUserCaptureScreen enable: " + flag + " success: " + JSON.stringify(res));
}, },
fail: (res) => { fail: (res) => {
console.log("setUserCaptureScreen open: " + flag + " fail: " + JSON.stringify(res)); console.log("setUserCaptureScreen enable: " + flag + " fail: " + JSON.stringify(res));
}, },
complete: (res) => { complete: (res) => {
console.log("setUserCaptureScreen open: " + flag + " complete: " + JSON.stringify(res)); console.log("setUserCaptureScreen enable: " + flag + " complete: " + JSON.stringify(res));
} }
}); });
uni.showToast({ uni.showToast({
......
import { UTSAndroid } from "io.dcloud.uts";
import {
UTSAndroid
} from "io.dcloud.uts";
import ActivityCompat from "androidx.core.app.ActivityCompat"; import ActivityCompat from "androidx.core.app.ActivityCompat";
import Manifest from "android.Manifest"; import Manifest from "android.Manifest";
import PackageManager from "android.content.pm.PackageManager"; import PackageManager from "android.content.pm.PackageManager";
...@@ -14,167 +8,134 @@ import File from "java.io.File"; ...@@ -14,167 +8,134 @@ import File from "java.io.File";
import Environment from "android.os.Environment"; import Environment from "android.os.Environment";
import System from 'java.lang.System'; import System from 'java.lang.System';
import WindowManager from 'android.view.WindowManager'; import WindowManager from 'android.view.WindowManager';
import { SetUserCaptureScreenOption, UserCaptureScreenResult, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen } from "../interface.uts"; import { UserCaptureScreenResult, OnUserCaptureScreenResult, SetUserCaptureScreenOptions, UserCaptureScreenCallback, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen } from "../interface.uts";
/** /**
* 文件监听器 * 文件监听器
*/ */
let screenOB: ScreenFileObserver | null = null; let observer : ScreenFileObserver | null = null;
/** /**
* 记录文件监听器上次监听的时间戳,避免重复监听 * 记录文件监听器上次监听的时间戳,避免重复监听
*/ */
let lastFileObserverTime: number = 0; let lastObserverTime : number = 0;
/** /**
* 图片被捕获的实现 * 截屏回调
*/ */
let imageChange: UTSCallback | null = null; let listener : UserCaptureScreenCallback | null = null;
/** /**
* android 文件监听实现 * android 文件监听实现
*/ */
@Suppress("DEPRECATION")
class ScreenFileObserver extends FileObserver { class ScreenFileObserver extends FileObserver {
/** /**
* 所有截屏文件的存放目录 * 截屏文件目录
*/ */
allScreen: File; private screenFile : File;
constructor(screenFile : File) {
constructor(screenFile: string) { super(screenFile);
super(new File(screenFile)) this.screenFile = screenFile;
this.allScreen = new File(screenFile);
} }
override onEvent(event : Int, path : string | null) : void {
override onEvent(event: Int, path?: string): void {
// 只监听文件新增事件 // 只监听文件新增事件
if (event == FileObserver.CREATE) { if (event == FileObserver.CREATE) {
if (path != null) {
let newPath: string = new File(this.allScreen, path!).getPath(); const currentTime = System.currentTimeMillis();
let currentTime = System.currentTimeMillis(); if ((currentTime - lastObserverTime) < 1000) {
// 本地截屏行为比上一次超过1000ms, 才认为是一个有效的时间
if ((currentTime - lastFileObserverTime) < 1000) { return;
// 本地截屏行为比上一次超过1000ms,才认为是一个有效的时间 }
return; lastObserverTime = currentTime;
}
const screenShotPath = new File(this.screenFile, path).getPath();
lastFileObserverTime = System.currentTimeMillis() const res : OnUserCaptureScreenResult = {
let ret = { errCode: 0,
errCode:1, errMsg: "onUserCaptureScreen:ok",
image:newPath errSubject: "uni-onUserCaptureScreen",
path: screenShotPath
}
listener?.(res);
} }
imageChange!(ret);
} }
} }
} }
/** /**
* 开启截图监听 * 开启截图监听
*/ */
@Suppress("DEPRECATION") export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UTSCallback) { // 检查相关权限是否已授予
if (ActivityCompat.checkSelfPermission(UTSAndroid.getAppContext()!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 检查相关权限是否已经具备 // 无权限,申请权限,并且告知用户监听失败
if (ActivityCompat.checkSelfPermission(UTSAndroid.getUniActivity()!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(UTSAndroid.getUniActivity()!, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1001);
// 不具备权限,申请权限,并且告知用户监听失败
ActivityCompat.requestPermissions(UTSAndroid.getUniActivity()!, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1001)
// 因权限缺失导致监听失败 // 因权限缺失导致监听失败
let ret = { const res : OnUserCaptureScreenResult = {
errCode:-1 errCode: -1,
errMsg: "onUserCaptureScreen:permission denied",
errSubject: "uni-onUserCaptureScreen"
} }
callback(ret); callback?.(res);
return ; return;
} }
imageChange = callback;
let directory_screenshot: File; // 更新监听
// 找到设备存放截屏文件的目录 listener = callback;
let directory_pictures = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
let directory_dcim = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM); let directory_screenshot : File;
if (Build.MANUFACTURER.toLowerCase() === "xiaomi") { if (Build.MANUFACTURER.toLowerCase() === "xiaomi") {
directory_screenshot = new File(directory_dcim, "Screenshots"); // @Suppress("DEPRECATION")
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM), "Screenshots");
} else { } else {
directory_screenshot = new File(directory_pictures, "Screenshots"); // @Suppress("DEPRECATION")
directory_screenshot = new File(new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES), "Screenshots");
} }
// 先结束监听 再开启监听
if (screenOB != null) { observer?.stopWatching();
screenOB!.stopWatching() observer = new ScreenFileObserver(directory_screenshot);
} observer?.startWatching();
//开始监听
screenOB = new ScreenFileObserver(directory_screenshot.path)
screenOB!.startWatching()
// 监听成功
let ret = {
errCode:0
}
callback(ret);
} }
/** /**
* 关闭截屏监听 * 关闭截屏监听
*/ */
export const offUserCaptureScreen : OffUserCaptureScreen = function (callback : UTSCallback) { export const offUserCaptureScreen : OffUserCaptureScreen = function (_ : UserCaptureScreenCallback | null) {
// android10以上,关闭监听通过移除文件监听器实现
// android 10以上,关闭监听通过移除文件监听器实现 observer?.stopWatching();
if (screenOB != null) { observer = null;
screenOB!.stopWatching() lastObserverTime = 0;
screenOB = null
}
lastFileObserverTime = 0;
callback({});
} }
/** /**
* 设置是否禁止截屏 * 设置是否禁止截屏
*/ */
export const setUserCaptureScreen : SetUserCaptureScreen = function (option: SetUserCaptureScreenOption) { export const setUserCaptureScreen : SetUserCaptureScreen = function (option : SetUserCaptureScreenOptions) {
// 切换到UI线程 // 切换到UI线程
UTSAndroid.getUniActivity()?.runOnUiThread(new SetUserCaptureScreenRunnable(option.enable)); UTSAndroid.getUniActivity()?.runOnUiThread(new SetUserCaptureScreenRunnable(option.enable));
const res = new UserCaptureScreenResult(); const res : UserCaptureScreenResult = {
res.errCode = 0; errCode: 0,
res.errMsg = "setUserCaptureScreen:ok"; errMsg: "setUserCaptureScreen:ok",
res.errSubject = "uni-setUserCaptureScreen"; errSubject: "uni-setUserCaptureScreen"
}
option.success?.(res); option.success?.(res);
option.complete?.(res); option.complete?.(res);
} }
class SetUserCaptureScreenRunnable extends Runnable { class SetUserCaptureScreenRunnable extends Runnable {
/** /**
* ture: 允许用户截屏 * ture: 允许用户截屏
* false: 不允许用户截屏,防止用户截屏到应用页面内容 * false: 不允许用户截屏,防止用户截屏到应用页面内容
*/ */
private enable: boolean; private enable : boolean;
constructor(enable: boolean) { constructor(enable : boolean) {
super(); super();
this.enable = enable; this.enable = enable;
} }
override run(): void { override run() : void {
if (this.enable) { if (this.enable) {
UTSAndroid.getUniActivity()?.getWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); UTSAndroid.getUniActivity()?.getWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
} else { } else {
...@@ -182,6 +143,3 @@ class SetUserCaptureScreenRunnable extends Runnable { ...@@ -182,6 +143,3 @@ class SetUserCaptureScreenRunnable extends Runnable {
} }
} }
} }
import { NotificationCenter } from 'Foundation'; import { NotificationCenter } from 'Foundation';
import { CGRect } from "CoreFoundation"; import { CGRect } from "CoreFoundation";
import { UIApplication, UIView, UITextField, UIScreen, UIDevice } from "UIKit" import { UIApplication, UIView, UITextField, UIScreen, UIDevice } from "UIKit"
import { UTSiOS, UTSCallback } from "DCloudUTSFoundation" import { UTSiOS } from "DCloudUTSFoundation"
import { DispatchQueue } from 'Dispatch'; import { DispatchQueue } from 'Dispatch';
import { SetUserCaptureScreenOption, UserCaptureScreenResult, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen } from "../interface.uts" import { SetUserCaptureScreenOptions, UserCaptureScreenResult, OnUserCaptureScreen, OffUserCaptureScreen, SetUserCaptureScreen, UserCaptureScreenCallback, OnUserCaptureScreenResult } from "../interface.uts"
/** /**
* 定义监听截屏事件工具类 * 定义监听截屏事件工具类
*/ */
class CaptureScreenTool { class CaptureScreenTool {
static listener ?: UTSCallback; static listener : UserCaptureScreenCallback | null;
static secureView ?: UIView; static secureView : UIView | null;
// 监听截屏 // 监听截屏
static listenCaptureScreen(callback ?: UTSCallback) { static listenCaptureScreen(callback : UserCaptureScreenCallback | null) {
this.listener = callback this.listener = callback
// 注册监听截屏事件及回调方法 // 注册监听截屏事件及回调方法
// target-action 回调方法需要通过 Selector("方法名") 构建 // target-action 回调方法需要通过 Selector("方法名") 构建
const method = Selector("userDidTakeScreenshot") const method = Selector("userDidTakeScreenshot")
...@@ -25,35 +25,45 @@ class CaptureScreenTool { ...@@ -25,35 +25,45 @@ class CaptureScreenTool {
// 捕获截屏回调的方法 // 捕获截屏回调的方法
// target-action 的方法前需要添加 @objc 前缀 // target-action 的方法前需要添加 @objc 前缀
@objc static userDidTakeScreenshot() { @objc static userDidTakeScreenshot() {
// 回调 // 回调
this.listener?.({}) const res: OnUserCaptureScreenResult = {
errCode: 0,
errSubject: "uni-usercapturescreen",
errMsg: "onUserCaptureScreen: ok",
path: null
}
this.listener?.(res)
} }
// 移除监听事件 // 移除监听事件
static removeListen(callback ?: UTSCallback) { static removeListen(callback : UserCaptureScreenCallback | null) {
this.listener = null this.listener = null
NotificationCenter.default.removeObserver(this) NotificationCenter.default.removeObserver(this)
callback?.({}) const res: OnUserCaptureScreenResult = {
errCode: 0,
errSubject: "uni-usercapturescreen",
errMsg: "offUserCaptureScreen: ok",
path: null
}
callback?.(res)
} }
static createSecureView() : UIView | null { static createSecureView() : UIView | null {
let field = new UITextField(frame = CGRect.zero) let field = new UITextField(frame = CGRect.zero)
field.isSecureTextEntry = true field.isSecureTextEntry = true
if (field.subviews.count > 0 && UIDevice.current.systemVersion != '15.1') { if (field.subviews.length > 0 && UIDevice.current.systemVersion != '15.1') {
let view = field.subviews.first let view = field.subviews[0]
if (view != null) { view.subviews.forEach((item) => {
view!.subviews.forEach((item) => { item.removeFromSuperview()
item.removeFromSuperview() })
}) view.isUserInteractionEnabled = true
view!.isUserInteractionEnabled = true return view
return view
}
} }
return null return null
} }
// 开启防截屏 // 开启防截屏
static onAntiScreenshot(option : SetUserCaptureScreenOption) { static onAntiScreenshot(option : SetUserCaptureScreenOptions) {
// uts方法默认会在子线程中执行,涉及 UI 操作必须在主线程中运行,通过 DispatchQueue.main.async 方法可将代码在主线程中运行 // uts方法默认会在子线程中执行,涉及 UI 操作必须在主线程中运行,通过 DispatchQueue.main.async 方法可将代码在主线程中运行
DispatchQueue.main.async(execute = () : void => { DispatchQueue.main.async(execute = () : void => {
let secureView = this.createSecureView() let secureView = this.createSecureView()
...@@ -70,18 +80,19 @@ class CaptureScreenTool { ...@@ -70,18 +80,19 @@ class CaptureScreenTool {
secureView!.frame = UIScreen.main.bounds secureView!.frame = UIScreen.main.bounds
rootView!.frame = rect rootView!.frame = rect
} }
}
let res: UserCaptureScreenResult = {
errCode: 0,
errSubject: "uni-usercapturescreen",
errMsg: "setUserCaptureScreen:ok"
} }
let res = new UserCaptureScreenResult()
res.errCode = 0;
res.errSubject = "uni-usercapturescreen";
res.errMsg = "setUserCaptureScreen:ok";
option.success?.(res) option.success?.(res)
option.complete?.(res) option.complete?.(res)
}) })
} }
// 关闭防截屏 // 关闭防截屏
static offAntiScreenshot(option : SetUserCaptureScreenOption) { static offAntiScreenshot(option : SetUserCaptureScreenOptions) {
DispatchQueue.main.async(execute = () : void => { DispatchQueue.main.async(execute = () : void => {
if (this.secureView != null) { if (this.secureView != null) {
let window = UTSiOS.getKeyWindow() let window = UTSiOS.getKeyWindow()
...@@ -94,11 +105,12 @@ class CaptureScreenTool { ...@@ -94,11 +105,12 @@ class CaptureScreenTool {
} }
} }
this.secureView = null this.secureView = null
}
let res: UserCaptureScreenResult = {
errCode: 0,
errSubject: "uni-usercapturescreen",
errMsg: "setUserCaptureScreen:ok"
} }
let res = new UserCaptureScreenResult()
res.errCode = 0;
res.errSubject = "uni-usercapturescreen";
res.errMsg = "setUserCaptureScreen:ok";
option.success?.(res) option.success?.(res)
option.complete?.(res) option.complete?.(res)
}) })
...@@ -108,34 +120,36 @@ class CaptureScreenTool { ...@@ -108,34 +120,36 @@ class CaptureScreenTool {
/** /**
* 开启截图监听 * 开启截图监听
*/ */
export const onUserCaptureScreen : OnUserCaptureScreen = function (callback ?: UTSCallback) { export const onUserCaptureScreen : OnUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
CaptureScreenTool.listenCaptureScreen(callback) CaptureScreenTool.listenCaptureScreen(callback)
} }
/** /**
* 关闭截屏监听 * 关闭截屏监听
*/ */
export const offUserCaptureScreen : OffUserCaptureScreen = function (callback ?: UTSCallback) { export const offUserCaptureScreen : OffUserCaptureScreen = function (callback : UserCaptureScreenCallback | null) {
CaptureScreenTool.removeListen(callback) CaptureScreenTool.removeListen(callback)
} }
/** /**
* 开启/关闭防截屏 * 开启/关闭防截屏
*/ */
export const setUserCaptureScreen : SetUserCaptureScreen = function (options : SetUserCaptureScreenOption) { export const setUserCaptureScreen : SetUserCaptureScreen = function (options : SetUserCaptureScreenOptions) {
if (UIDevice.current.systemVersion < "13.0") { if (UIDevice.current.systemVersion < "13.0") {
let res = new UserCaptureScreenResult() let res: UserCaptureScreenResult = {
res.errCode = 12001; errCode: 12001,
res.errSubject = "uni-usercapturescreen"; errSubject: "uni-usercapturescreen",
res.errMsg = "setUserCaptureScreen:system not support"; errMsg: "setUserCaptureScreen:system not support"
}
options.fail?.(res); options.fail?.(res);
options.complete?.(res); options.complete?.(res);
} else if (UIDevice.current.systemVersion == "15.1") { } else if (UIDevice.current.systemVersion == "15.1") {
let res = new UserCaptureScreenResult() let res: UserCaptureScreenResult = {
res.errCode = 12010; errCode: 12010,
res.errSubject = "uni-usercapturescreen"; errSubject: "uni-usercapturescreen",
res.errMsg = "setUserCaptureScreen:system internal error"; errMsg: "setUserCaptureScreen:system internal error"
}
options.fail?.(res); options.fail?.(res);
options.complete?.(res); options.complete?.(res);
} else { } else {
......
...@@ -2,6 +2,7 @@ export type UserCaptureScreenResult = { ...@@ -2,6 +2,7 @@ export type UserCaptureScreenResult = {
/** /**
* 错误码 * 错误码
* 0:成功 * 0:成功
* -1:permission denied
* 12001:system not support * 12001:system not support
* 12010:system internal error * 12010:system internal error
*/ */
...@@ -16,7 +17,28 @@ export type UserCaptureScreenResult = { ...@@ -16,7 +17,28 @@ export type UserCaptureScreenResult = {
errMsg : string, errMsg : string,
} }
export type SetUserCaptureScreenOption = { export type OnUserCaptureScreenResult = {
/**
* 错误码
* 0:成功
* -1:permission denied(仅Android返回)
*/
errCode : number,
/**
* 调用API的名称
*/
errSubject : string,
/**
* 错误的详细信息
*/
errMsg : string,
/**
* 截屏文件路径(仅Android返回)
*/
path : string | null
}
export type SetUserCaptureScreenOptions = {
/** /**
* true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容 * true: 允许用户截屏 false: 不允许用户截屏,防止用户截屏到应用页面内容
*/ */
...@@ -35,35 +57,37 @@ export type SetUserCaptureScreenOption = { ...@@ -35,35 +57,37 @@ export type SetUserCaptureScreenOption = {
complete ?: (res : UserCaptureScreenResult) => void complete ?: (res : UserCaptureScreenResult) => void
} }
export type UserCaptureScreenCallback = (res : OnUserCaptureScreenResult) => void
/** /**
* 开启截屏监听 * 开启截屏监听
* *
* @param {UTSCallback} callback * @param {UserCaptureScreenCallback} callback
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen * @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen
* @platforms APP-IOS = ^9.0,APP-ANDROID = ^22 * @platforms APP-IOS = ^9.0,APP-ANDROID = ^22
* @since 3.6.8 * @since 3.6.8
*/ */
export type OnUserCaptureScreen = (callback ?: UTSCallback) => void export type OnUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
/** /**
* 关闭截屏监听 * 关闭截屏监听
* *
* @param {UTSCallback} callback * @param {UserCaptureScreenCallback} callback
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen * @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen
* @platforms APP-IOS = ^9.0,APP-ANDROID = ^22 * @platforms APP-IOS = ^9.0,APP-ANDROID = ^22
* @since 3.6.8 * @since 3.6.8
*/ */
export type OffUserCaptureScreen = (callback ?: UTSCallback) => void export type OffUserCaptureScreen = (callback : UserCaptureScreenCallback | null) => void
/** /**
* 设置防截屏 * 设置防截屏
* *
* @param {SetUserCaptureScreenOption} options * @param {SetUserCaptureScreenOptions} options
* @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen * @tutorial https://uniapp.dcloud.net.cn/api/system/capture-screen.html#setusercapturescreen
* @platforms APP-IOS = ^9.0,APP-ANDROID = ^22 * @platforms APP-IOS = ^9.0,APP-ANDROID = ^22
* @since 3.7.3 * @since 3.7.3
*/ */
export type SetUserCaptureScreen = (options : SetUserCaptureScreenOption) => void export type SetUserCaptureScreen = (options : SetUserCaptureScreenOptions) => void
interface uni { interface uni {
onUserCaptureScreen : OnUserCaptureScreen, onUserCaptureScreen : OnUserCaptureScreen,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册