提交 954a5c4c 编写于 作者: 杜庆泉's avatar 杜庆泉

android 增加 widget示例

上级 4ae3f505
## 1.0.1(2022-10-27)
修改插件描述
## 1.0.0(2022-10-26)
支持安卓、iOS、微信小程序平台
type OnUserCaptureScreenCallback = (res?: { errMsg: string }) => void
declare class Uni {
/**
* 监听用户主动截屏事件,用户使用系统截屏按键截屏时触发此事件。
*
* 文档: [https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#onusercapturescreen)
*/
onUserCaptureScreen(callback: OnUserCaptureScreenCallback): void;
/**
* 用户主动截屏事件。取消事件监听。
*
* 文档: [https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen](https://uniapp.dcloud.net.cn/api/system/capture-screen.html#offusercapturescreen)
*/
offUserCaptureScreen(callback: OnUserCaptureScreenCallback): void;
}
{
"id": "uni-usercapturescreen",
"displayName": "uni-usercapturescreen",
"version": "1.0.1",
"description": "用户主动截屏事件监听",
"keywords": [
"截屏"
],
"repository": "",
"engines": {
"HBuilderX": "^3.6.0"
},
"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": "onUserCaptureScreen",
"offUserCaptureScreen": "offUserCaptureScreen"
}
},
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "n",
"vue3": "y"
},
"App": {
"app-android": "y",
"app-ios": "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"
}
}
}
}
}
# 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)
import {
getUniActivity
} from "io.dcloud.uts.android";
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';
/**
* 文件监听器
*/
let screenOB: ScreenFileObserver | null = null;
/**
* 记录文件监听器上次监听的时间戳,避免重复监听
*/
let lastFileObserverTime: number = 0;
/**
* 图片被捕获的实现
*/
let imageChange: UTSCallback | null = null;
/**
* android 文件监听实现
*/
class ScreenFileObserver extends FileObserver {
/**
* 所有截屏文件的存放目录
*/
allScreen: File;
constructor(screenFile: string) {
super(screenFile)
this.allScreen = new File(screenFile);
}
override onEvent(event: Int, path?: string): void {
// 只监听文件新增事件
if (event == FileObserver.CREATE) {
let newPath: string = new File(this.allScreen, path!).getPath();
let currentTime = System.currentTimeMillis();
if ((currentTime - lastFileObserverTime) < 1000) {
// 本地截屏行为比上一次超过1000ms,才认为是一个有效的时间
return;
}
lastFileObserverTime = System.currentTimeMillis()
let ret = {
errCode:1,
image:newPath
}
imageChange!(ret);
}
}
}
/**
* 开启截图监听
*/
export function onUserCaptureScreen(callback: (res:UTSJSONObject) => void) {
// 检查相关权限是否已经具备
if (ActivityCompat.checkSelfPermission(getUniActivity()!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 不具备权限,申请权限,并且告知用户监听失败
ActivityCompat.requestPermissions(getUniActivity()!, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1001)
// 因权限缺失导致监听失败
let ret = {
errCode:-1
}
callback(ret);
return ;
}
imageChange = callback;
let directory_screenshot: File;
// 找到设备存放截屏文件的目录
let directory_pictures = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
let directory_dcim = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_DCIM);
if (Build.MANUFACTURER.lowercase() === "xiaomi") {
directory_screenshot = new File(directory_dcim, "Screenshots");
} else {
directory_screenshot = new File(directory_pictures, "Screenshots");
}
if (screenOB != null) {
screenOB!.stopWatching()
}
//开始监听
screenOB = new ScreenFileObserver(directory_screenshot.path)
screenOB!.startWatching()
// 监听成功
let ret = {
errCode:0
}
callback(ret);
}
/**
* 关闭截屏监听
*/
export function offUserCaptureScreen(success: (res: any) => void) {
// android 10以上,关闭监听通过移除文件监听器实现
if (screenOB != null) {
screenOB!.stopWatching()
screenOB = null
}
lastFileObserverTime = 0;
success({});
}
import { NotificationCenter} from 'Foundation';
import { UIApplication } from "UIKit"
/**
* 定义监听截屏事件工具类
*/
class CaptureScreenTool {
static listener?: UTSCallback;
// 监听截屏
static listenCaptureScreen(callback?: UTSCallback) {
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 obj = new UTSJSONObject()
// 回调
this.listener?.(obj)
}
// 移除监听事件
static removeListen(callback?: UTSCallback) {
this.listener = null
NotificationCenter.default.removeObserver(this)
const obj = new UTSJSONObject()
callback?.(obj)
}
}
/**
* 开启截图监听
*/
export function onUserCaptureScreen(callback?: UTSCallback) {
CaptureScreenTool.listenCaptureScreen(callback)
}
/**
* 关闭截屏监听
*/
export function offUserCaptureScreen(callback?: UTSCallback) {
CaptureScreenTool.removeListen(callback)
}
export function onUserCaptureScreen (callback) {
return wx.onUserCaptureScreen(callback)
}
export function offUserCaptureScreen (callback) {
return wx.offUserCaptureScreen(callback)
}
......@@ -7,5 +7,17 @@
<application>
<service android:name="uts.sdk.modules.utsNativepage.ForeService" />
<activity android:name="uts.sdk.modules.utsNativepage.DemoActivity"></activity>
<!--桌面widget组件注册-->
<receiver
android:name="uts.sdk.modules.utsNativepage.DoAppWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/do_app_widget_info" />
</receiver>
</application>
</manifest>
import AppWidgetProvider from 'android.appwidget.AppWidgetProvider';
import Context from 'android.content.Context';
import AppWidgetManager from 'android.appwidget.AppWidgetManager';
import RemoteViews from 'android.widget.RemoteViews';
import Handler from 'android.os.Handler';
import UTSAndroid from 'io.dcloud.uts.UTSAndroid';
import R from 'io.dcloud.uni_modules.uts_nativepage.R';
export class DoAppWidget extends AppWidgetProvider {
constructor(){
super()
console.log("DoAppWidget")
}
override onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
):void{
console.log("dqqdo", "周期更新函数被触发")
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override onEnabled(_context: Context):void{
// Enter relevant functionality for when the first widget is created
console.log("dqqdo", "桌面组件被添加")
}
override onDisabled(_context: Context):void{
// Enter relevant functionality for when the last widget is disabled
console.log("dqqdo", "桌面组件被移除")
}
}
/**
* Dialog ui任务封装
*/
class UIRunnable extends Runnable {
context: Context;
appWidgetManager: AppWidgetManager;
appWidgetId: Int;
widgetText:string;
constructor(contextP:Context,appWidgetManagerP: AppWidgetManager,appWidgetIdP: Int,widgetTextP:string){
super();
this.context = contextP
this.appWidgetManager = appWidgetManagerP
this.appWidgetId = appWidgetIdP
this.widgetText = widgetTextP;
}
override run() {
let views = new RemoteViews(this.context.packageName, R.layout.do_app_widget)
views.setTextViewText(R.id.appwidget_text_sub, this.widgetText)
// Instruct the widget manager to update the widget
this.appWidgetManager.updateAppWidget(this.appWidgetId, views)
}
};
function updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
let widgetText = "当前股票价格为:0.0元"
setTimeout(function(){
// 模拟请求网络,这里需要替换成真正的网络请求
Thread.sleep(1000)
widgetText = "当前股票价格为:13.25元"
let uiRunnable = new UIRunnable(context,appWidgetManager,appWidgetId,widgetText)
// 更新UI
UTSAndroid.getUniActivity()!.runOnUiThread(uiRunnable)
},500);
}
\ No newline at end of file
......@@ -33,13 +33,10 @@ import TextView from 'android.widget.TextView';
import ViewGroup from 'android.view.ViewGroup';
import LayoutInflater from 'android.view.LayoutInflater';
import LinearLayoutManager from 'androidx.recyclerview.widget.LinearLayoutManager';
export {DoAppWidget} from "./DoAppWidget.uts"
class ForeService extends Service {
constructor (){
super();
}
......
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.WidgetTest.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:theme="@style/Theme.WidgetTest.AppWidgetContainer">
<TextView
android:id="@+id/appwidget_text"
style="@style/Widget.WidgetTest.AppWidget.InnerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:text="桌面小组件"
android:textSize="10sp"
android:textStyle="bold|italic" />
<TextView
android:id="@+id/appwidget_text_sub"
style="@style/Widget.WidgetTest.AppWidget.InnerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:text="模拟请求内容"
android:textSize="10sp"
/>
</LinearLayout>
\ No newline at end of file
<resources>
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
</resources>
\ No newline at end of file
......@@ -11,4 +11,5 @@
<string name="dcloud_ad_notification_pause_download">Pause</string>
<string name="dcloud_ad_notification_delete_download">Delete</string>
<string name="dcloud_ad_tag_ads">Ads</string>
<string name="app_widget_description">This is an app widget description</string>
</resources>
\ No newline at end of file
<resources>
<style name="Widget.WidgetTest.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">?android:attr/colorBackground</item>
</style>
<style name="Widget.WidgetTest.AppWidget.InnerView" parent="android:Widget">
<item name="android:background">?android:attr/colorBackground</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>
\ No newline at end of file
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.WidgetTest.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
<!-- Radius of the outer bound of widgets to make the rounded corners -->
<item name="appWidgetRadius">12dp</item>
<!--
Radius of the inner view's bound of widgets to make the rounded corners.
It needs to be 8dp or less than the value of appWidgetRadius
-->
<item name="appWidgetInnerRadius">6dp</item>
</style>
<style name="Theme.WidgetTest.AppWidgetContainer" parent="Theme.WidgetTest.AppWidgetContainerParent">
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
<item name="appWidgetPadding">6dp</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:initialKeyguardLayout="@layout/do_app_widget"
android:initialLayout="@layout/do_app_widget"
android:minWidth="120dp"
android:minHeight="40dp"
android:previewImage="@drawable/example_appwidget_preview"
android:previewLayout="@layout/do_app_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="1"
android:targetCellHeight="1"
android:updatePeriodMillis="1800000"
android:widgetCategory="home_screen" />
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册