Android 应用添加系统签名权限的几种方式实现介绍
Android 应用添加系统签名权限的几种方式实现介绍
文章目录
- Android 应用添加系统签名权限的几种方式实现介绍
- 一、前言
- 二、Android 应用添加系统签名权限的几种方式介绍
- 1、在Android Studio添加系统签名文件
- 2、源码编译apk添加系统签名
- Android.mk
- Android.bp
- 3、源码编译app代码添加系统签名
- Android.mk
- Android.bp
- 三、缺少系统权限报错示例
- 1、设置Settings属性报错
- 2、设置Wifi开关状态失败
- 3、Settings属性设置为啥需要系统权限?
- 4、设置Wifi开关状态为啥失败?
- 四、其他
- 1、系统权限介绍
- (1)普通权限(normal)
- (2)运行时权限(dangerous)
- (3)签名权限(signature)
- (4)特殊权限(privileged)
- 2、如何查看一个应用的权限情况?
- 3、系统权限级别总结
- Android中不同应用权限级别从低到高总结场景
- 4、Android APEX:系统新篇章的应用扁平化技术
一、前言
Android 应用添加系统签名就能获取到系统权限调用一些系统接口,
添加系统签名的方式主要包括:
在Android Studio中配置签名文件生成apk 和 在源码目录编译添加系统签名生成apk。
本文介绍的都是一些基础的签名知识,后续延伸介绍相关权限内容。有兴趣的可以进行了解。
二、Android 应用添加系统签名权限的几种方式介绍
1、在Android Studio添加系统签名文件
源码中生成 jks 签名文件:
https://blog.csdn.net/wenzhi20102321/article/details/134898404
Studio 在对应需要签名的module(默认是app)的build.gradle中添加如下代码:
android {compileSdkVersion 30buildToolsVersion "30.0.0"compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
。。。//证书信息在这里配置signingConfigs {main {storeFile file("./platform.jks") //签名文件路径,根目录storePassword "skg202302"keyAlias "skg"keyPassword "skg202302"}}buildTypes {release {minifyEnabled falsesigningConfig signingConfigs.main //添加这一行proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}debug {minifyEnabled falsesigningConfig signingConfigs.main //添加这一行proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}}
只是添加了系统签名是不行的,还需要在AndroidManifest.xml中声明系统权限
AndroidManifest.xml 配置uid系统权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"coreApp="true"package="com.xxx.xxx"android:sharedUserId="android.uid.system">
2、源码编译apk添加系统签名
如果apk没有签名文件和为添加签名信息,那么添加uid.system后,该应用是无法安装到对应系统上的;
如果要安装可以在源码里面编译,生成的apk就会加入签名的信息的。
Android.mk
# 编译的目录,默认写法
include $(CLEAR_VARS)# 设置模块名
LOCAL_MODULE := mymodule# 设置预构建文件的源路径和目标路径
LOCAL_SRC_FILES := path/file.apk# 设置系统权限和目录
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true
# 设置是否编译在 priv-app,如果没有指定目录默认为 system/priv-app
LOCAL_PRIVILEGED_MODULE := true include $(BUILD_PREBUILT)
Android.bp
android_app_import {name: "FileManager",apk: "FileManager.apk",//生成到priv-app目录下privileged: true,//使用系统签名certificate: "platform",
}
3、源码编译app代码添加系统签名
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)# 设置模块名为myapp
LOCAL_MODULE := myapp
# 添加需要编译的Java源文件
LOCAL_SRC_FILES := $(wildcard *.java)
# 添加需要编译的资源文件
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
# 设置输出APK的路径和名称
LOCAL_PACKAGE_NAME := myapp# 设置系统权限和目录
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true
# 设置是否编译在 priv-app,如果没有指定目录默认为 system/app
LOCAL_PRIVILEGED_MODULE := true include $(BUILD_PACKAGE)
Android.bp
android_app {name: "myapp",srcs: ["path/to/your/app/src/**/*.java",],resource_dirs: ["path/to/your/app/res",],manifest: "path/to/your/app/AndroidManifest.xml",//加载类库static_libs: ["mylibrary",],//是否系统签名certificate: "platform",platform_apis: true,//是否生成到priv-app目录privileged: true,}
上面是代码的情况,编译apk获取系统签名的
Android13或者更新的源代码,大多都是使用Android.bp进行编译。
上面就是本文的主要内容,下面是一些相关内容知识。
三、缺少系统权限报错示例
这里以Settings设置属性为示例讲解。
Settings属性获取是不需要权限的,Settings属性设置是需要权限的,为啥会这样?
其实是因为代码里面定义的,具体是哪个类的哪行代码限制的?有兴趣的可以往下看看:
//Settings 获取属性值,不用权限和签名
int value = Settings.Global.getInt(getContentResolver(), Settings.Global.WIFI_ON, -1);//Settings 设置属性值,需要系统签名或者系统权限,否则会异常
boolean value = Settings.Global.putInt(getContentResolver(), Settings.Global.WIFI_ON, 1);//Wifi开关控制,需要系统签名或者系统权限,否则返回false,但是不会异常
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
boolean value = wifiManager.setWifiEnabled(true);
1、设置Settings属性报错
设置wifi开关状态报错:
Caused by: java.lang.SecurityException: Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGSat android.os.Parcel.createExceptionOrNull(Parcel.java:3011)at android.os.Parcel.createException(Parcel.java:2995)at android.os.Parcel.readException(Parcel.java:2978)at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:190)at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:142)at android.content.ContentProviderProxy.call(ContentProviderNative.java:732)at android.provider.Settings$NameValueCache.putStringForUser(Settings.java:3021)at android.provider.Settings$Global.putStringForUser(Settings.java:16753)at android.provider.Settings$Global.putString(Settings.java:16594)at android.provider.Settings$Global.putInt(Settings.java:16824)at com.demo.systemapp.MainActivity.setSettingsValue(MainActivity.java:29)at java.lang.reflect.Method.invoke(Native Method)
从报错日志看是缺少了权限:WRITE_SECURE_SETTINGS。这个权限是需要签名或者系统应用才能拥有的权限。
如果要规避应用崩溃,可以通过try {}catch捕获异常,避免崩溃。
2、设置Wifi开关状态失败
调用wifi开关接口日志:
2024-01-20 17:09:04.193 638-1052/system_process I/WifiService: setWifiEnabled packageName = com.demo.systemapp, enable = true
2024-01-20 17:09:04.195 638-1052/system_process I/WifiService: setWifiEnabled not allowed for uid=10084
上面的日志都是 WifiServiceImpl.java 里面的日志。
显示了是哪个应用,调用了wifi开关的什么状态,后续显示not allowed ,因为uid = 100084,相当于啥都没做。
这种情况没有报错,也不会崩溃,但是就是调用了没效果。
所以大概可以猜测出需要设置Settings属性或者调用Wifi开关状态的接口都是要系统权限或者系统签名。
3、Settings属性设置为啥需要系统权限?
看看代码就知道了:
frameworks\base\core\java\android\provider\Settings.java
//Settings.XXX.Put属性需要权限的原因,代码这里定义了的。
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public static boolean putString(ContentResolver resolver,String name,String value,。。。){return putStringForUser(resolver, name, value, tag, makeDefault,resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
}
代码这里已经声明了,必须要系统应用和 WRITE_SECURE_SETTINGS权限,
才能调用后续的put方法,所以未获取到权限就会抛出异常。
4、设置Wifi开关状态为啥失败?
根据下面代码的具体判断就可以看得出:
packages\modules\Wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
//WifiManager.setWifiEnabled 失败原因,这里判断后返回了false
public synchronized boolean setWifiEnabled(String packageName, boolean enable) {//这里判断的是三方应用,主要是uid,三方应用不具有系统签名,所以返回false,不往下走if (isThirdParty && !isTargetSdkLessThanQ) {mLog.info("setWifiEnabled not allowed for uid=%").c(callingUid).flush();return false;}//这里判断是否是飞行模式并且是否不是系统应用(priv-app目录下的应用)//如果是飞行模式,并且不是priv-app目录的系统应用,返回false// If Airplane mode is enabled, only privileged apps are allowed to toggle Wifiif (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();return false;}//如果不是priv-app目录应用,并且热点开启的情况,返回false// If SoftAp is enabled, only privileged apps are allowed to toggle wifiif (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();return false;}...
}
上面是Android13 中wifi开关状态返回false的几种情况分析。
四、其他
1、系统权限介绍
framework 定义的所有 权限都是有定义包含 protectionLevel 等级的,主要权限等级有:普通,运行时,系统签名,特殊 。
(1)普通权限(normal)
此类权限允许访问超出应用沙盒的数据和执行超出应用沙盒的操作。但这些数据和操作对用户隐私及对其他应用的操作带来的风险非常小。
比如,上网权限,wifi 状态监听,蓝牙,获取后台任务等待,大概有一百多个。
(2)运行时权限(dangerous)
运行时权限也称为危险权限,此类权限授予应用对受限数据的额外访问权限,并允许应用执行对系统和其他应用具有更严重影响的受限操作。因此需要先在应用中请求运行时权限,然后才能访问受限数据或执行受限操作。当应用请求运行时权限时,系统会显示运行时权限弹窗提示。
比如,文件读写权限,日历读取和设置权限等待,总共不到一百个。
(3)签名权限(signature)
当应用声明了其他应用已定义的签名权限时,如果两个应用使用同一证书进行签名,系统会在安装时向前者授予该权限。否则,系统无法向前者授予该权限。(注意:有些签名权限不适合第三方应用使用。)
该权限只需要在manifest中声明使用,同时应用和这类权限定义者拥有一样的签名系统就会默认授予应用这类权限;系统授予这类权限后应用无需像运行时权限一样动态申请。
比如,Android11 新增的文件管理权限,对wifi,热点,Camera一些特殊操作权限,比较多,大概有五百多个。
(4)特殊权限(privileged)
特殊权限与特定的应用操作相对应。只有平台和原始设备制造商 (OEM) 可以定义特殊权限。此外,如果平台和 OEM 想要防止有人执行功能特别强大的操作(例如通过其他应用绘图),通常会定义特殊权限。系统设置中的特殊应用访问权限页面包含一组用户可切换的操作。其中的许多操作都以特殊权限的形式实现。每项特殊权限都有自己的实现细节。系统会为特殊权限分配“appop”保护级别。
比如本文的: 允许应用程序在所有用户之间进行交互 权限,启动前台服务权限,可通过overlay形式覆盖属性权限,应用主题更改监听等等,大概有三百多个。
一般情况下:特殊权限大部分与系统签名文件同时使用。
我们常用的广播都定义在framework\base\core\res\AndroidManifest.xml里面,如果要新增可以在里面新增
值得注意的是,系统签名文件是比系统应用权限大的,比如:
//MANAGE_CAMERA 权限,必须要系统签名才能获取到<permission android:name="android.permission.MANAGE_CAMERA"android:protectionLevel="signature" />//CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS 权限,系统签名或者priv-app应用都可以获取到<permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"android:protectionLevel="signature|privileged" />
上面的是 Android13 上比较新的权限定义,有兴趣的可以看看。
在线查看权限定义网址:
http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml
2、如何查看一个应用的权限情况?
dumpsys package XXX包名,可以查看apk信息:
E:\Studio\project\test\SystemApp>adb shell
rk3588_t:/ $ ^C
130|rk3588_t:/ $ dumpsys package com.demo.systemappPackages:Package [com.demo.systemapp] (6e1e98c): //1、应用包名userId=10083 //uid,system.uid = 10000pkg=Package{1a148d5 com.demo.systemapp}codePath=/system/app/SystemAppDemo //2、apk路径resourcePath=/system/app/SystemAppDemotimeStamp=2024-01-20 11:45:31lastUpdateTime=2024-01-20 11:45:31requested permissions: //3、AndroidManifest中声明的权限android.permission.WRITE_SECURE_SETTINGSandroid.permission.POST_NOTIFICATIONSUser 0: ceDataInode=9991 installed=true hidden=false suspended=false distractionFlags=0 stopped=false notLaunched=false enabled=0 instant=false virtual=falseinstallReason=0firstInstallTime=2024-01-20 11:45:31uninstallReason=0runtime permissions: //4、获取到的权限,granted=true 才算获取到!android.permission.POST_NOTIFICATIONS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]rk3588_t:/ $
E:\Studio\project\test\SystemApp>
从dumpsys package XXX 命令的日志,可以看到包名应用对应的Uid信息,版本信息,apk安装位置,安装时间,AndroidManifest声明的权限,实际获取到的权限等等信息。
requested permissions 下面的权限是应用声明的权限,runtime permissions的权限是当前获取到的权限。
值得注意的是即使是系统应用或者系统签名应用也是要在 AndroidManifest 中声明需要的权限。
3、系统权限级别总结
Android中不同应用权限级别从低到高总结场景
(1)普通应用。只用到了普通权限,比如上网权限等等。
(2)system/app 系统应用,用来可以限制无法手动卸载,对系统权限没有要求的情况,无法调用系统api
(3)system/priv-app 系统应用(未设置uid.system),无法手动卸载,可以调用部分系统api
(4)系统签名应用普通安装的方式,可以调用系统相关api,同时也可以被手动卸载,可以添加privileged特殊权限
(5)system/priv-app 系统应用(设置uid.system),无法手动卸载,可以调用全部系统api,可以添加privileged特殊权限
了解到不同的权限需求,应用要安装/编译在什么目录心里就有个底了。
4、Android APEX:系统新篇章的应用扁平化技术
Android13 和更新的版本编译,你会发现package/modules下面的代码模块都是编译到了目录: /system/apex/XXXPackage/XXX.apk
这里面的apk有些是系统签名应用,有些是普通应用,这个和具体的bp里面的编译规则相关。
APEX 的相关介绍:
https://blog.csdn.net/u011897062/article/details/133122565
https://blog.csdn.net/u010164190/article/details/122324409
这块知识看起来还是比较复杂。
对于普通应用开发者,和一般的系统应用开发者其实没啥研究价值。
可以简单的理解一下模块化的概念:比如把一个apk的某些模块编译成一个apk,这些模块可以接收广播处理事务或者启动服务处理事务等功能。
这个和应用开发中的模块化是同样的原理,只是源码中Android13 以前很少这样开发,后续更新的源码应该是会更多这样的模块。
相关文章:
Android 应用添加系统签名权限的几种方式实现介绍
Android 应用添加系统签名权限的几种方式实现介绍 文章目录 Android 应用添加系统签名权限的几种方式实现介绍一、前言二、Android 应用添加系统签名权限的几种方式介绍1、在Android Studio添加系统签名文件2、源码编译apk添加系统签名Android.mkAndroid.bp 3、源码编译app代码…...
麒麟V10+飞腾处理器源码编译qt
1.下载qt源码 2.百度解压命令,进行解压 3.cd进文件目录 4.使用./configure命令进行配置(重点:记得看说明) Usage: configure [-h] [-prefix <dir>] [-prefix-install] [-bindir <dir>] [-libdir <dir>][-docdir <dir>] [-headerdir <dir&g…...

MacOS 查AirPods 电量技巧:可实现低电量提醒、自动弹窗
要怎么透过macOS 来查询AirPods 电量呢?当AirPods 和Mac 配对后,有的朋友想通过Mac来查询AirPods有多少电量,这个里有几个技巧,下面我们来介绍一下。 透过Mac 查AirPods 电量技巧 技巧1. 利用状态列上音量功能查询 如要使用此功能…...

python介绍,安装Cpython解释器,IDE工具pycharm的使用
python介绍 官方的Python解释器本质是基于C语言开发的一个软件,该软件的功能就是读取以py.结尾的文件内容,然后按照Guido定义好的语法和规则去翻译并执行相应的代码。这种C实现的解释器被称为Cpython。 python解释器的种类:Jython IPyth…...

服务器安装Docker (centOS)
1. 卸载旧版本的Docker(如果有) 首先,如果您的系统上安装了旧版本的Docker,需要将其卸载。Docker的旧版本称为docker或docker-engine。使用以下命令来卸载旧版本: sudo yum remove docker \ docker-client \ docker-…...

解析spritf和sscanf与模拟常用字符串函数strchr,strtok(二)
今天又来继续我们的字符串函数的文章,这也是最后一篇了。希望这两篇文章能让各位理解透字符串函数。 目录 strchr strtok sprintf和sscanf strchr strchr 是一个用于在字符串中查找特定字符首次出现位置的函数。以下是解析和模拟实现 strchr 函数的示例&…...

备战蓝桥杯---搜索(进阶4)
话不多说,直接看题: 下面是分析: (ab)%c(a%cb%c)%c; (a*b)%c(a%c*b%c)%c; 因此,如果两个长度不一样的值%m为相同值,那就舍弃长的(因为再加1位只不过是原来值*10那位值,因此他们得出的%m还是同…...
51单片机基础(C语言):定时器时钟
1.使用定时器 1 和LCD1602设计一个简易数字时钟。 main.c #include <REGX52.H> #include "Delay.h" #include "LCD1602.h" #include "Timer0.h"unsigned char Sec55,Min59,Hour23;void main() {LCD_Init();Timer0Init();LCD_ShowString(…...

单片机无线发射的原理剖析
目录 一、EV1527编码格式 二、OOK&ASK的简单了解 三、433MHZ 四、单片机的地址ID 五、基于STC15W104单片机实现无线通信 无线发射主要运用到了三个知识点:EV1527格式;OOk;433MHZ。下面我们来分别阐述: EV1527是数据的编…...
Redis的过期键的删除策略
我们都知道,Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理。 过期策略通常有以下三种: 定时过期:每个设置过期时间的key都需要创建…...

放假--寒假自学版 day1(补2.5)
fread 函数: 今日练习 C语言面试题5道~ 1. static 有什么用途?(请至少说明两种) 1) 限制变量的作用域 2) 设置变量的存储域 2. 引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始…...

LLM(5) | Encoder 和 Decoder 架构
LLM(5) | Encoder 和 Decoder 架构 文章目录 LLM(5) | Encoder 和 Decoder 架构0. 目的1. 概要2. encoder 和 decoder 风格的 transformer (Encoder- And Decoder-Style Transformers)原始的 transformer (The original transformer)编码器 (Encoders)解码器 (Decoders)编码器和…...

CV | Medical-SAM-Adapter论文详解及项目实现
******************************* 👩⚕️ 医学影像相关直达👨⚕️******************************* CV | SAM在医学影像上的模型调研【20240207更新版】-CSDN博客 CV | Segment Anything论文详解及代码实现 本文主要讲解Medical-SAM-Adapter论文及项…...

C++初阶:容器(Containers)vector常用接口详解
介绍完了string类的相关内容后:C初阶:适合新手的手撕string类(模拟实现string类) 接下来进入新的篇章,容器vector介绍: 文章目录 1.vector的初步介绍2.vector的定义(constructor)3.v…...
flink写入es的参数解析
ElasticsearchSink内部使用BulkProcessor一次将一批动作(ActionRequest)发送到ES集群。在发送批量动作前,BulkProcessor先缓存,再刷新。缓存刷新的间隔,支持基于Action数量、基于Action大小、基于时间间隔3种策略。BulkProcessor支持在同一次…...

逆向工程:揭开科技神秘面纱的艺术
在当今这个科技飞速发展的时代,我们每天都在与各种电子产品、软件应用打交道。然而,你是否想过,这些看似复杂的高科技产品是如何被创造出来的?今天,我们就来探讨一下逆向工程这一神秘而又令人着迷的领域。 一、什么是…...

决策树的相关知识点
📕参考:ysu老师课件西瓜书 1.决策树的基本概念 【决策树】:决策树是一种描述对样本数据进行分类的树形结构模型,由节点和有向边组成。其中每个内部节点表示一个属性上的判断,每个分支代表一个判断结果的输出ÿ…...

【数据结构】单向链表实现 超详细
目录 一. 单链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项:帮助高效记忆和理解 2.链表的基本功能接口 2.0 创建一个 链表 2.1 链表的打印 3.链表的创建新节点接口 4.链表的节点插入功能接口 4.1 尾插接口 4.2 头插接口 4.3 指定位…...
Opencc4j 开源中文繁简体使用介绍
Opencc4j Opencc4j 支持中文繁简体转换,考虑到词组级别。 Features 特点 严格区分「一简对多繁」和「一简对多异」。 完全兼容异体字,可以实现动态替换。 严格审校一简对多繁词条,原则为「能分则不合」。 词库和函数库完全分离,…...

vue 下载二进制文件
文章目录 概要技术细节 概要 vue 下载后端返回的二进制文件流 技术细节 import axios from "axios"; const baseUrl process.env.VUE_APP_BASE_API; //downLoadPdf("/pdf/download?pdfName" res .pdf, res); export function downLoadPdf(str, fil…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...