当前位置: 首页 > news >正文

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 电量呢&#xff1f;当AirPods 和Mac 配对后&#xff0c;有的朋友想通过Mac来查询AirPods有多少电量&#xff0c;这个里有几个技巧&#xff0c;下面我们来介绍一下。 透过Mac 查AirPods 电量技巧 技巧1. 利用状态列上音量功能查询 如要使用此功能…...

python介绍,安装Cpython解释器,IDE工具pycharm的使用

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

服务器安装Docker (centOS)

1. 卸载旧版本的Docker&#xff08;如果有&#xff09; 首先&#xff0c;如果您的系统上安装了旧版本的Docker&#xff0c;需要将其卸载。Docker的旧版本称为docker或docker-engine。使用以下命令来卸载旧版本&#xff1a; sudo yum remove docker \ docker-client \ docker-…...

解析spritf和sscanf与模拟常用字符串函数strchr,strtok(二)

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

备战蓝桥杯---搜索(进阶4)

话不多说&#xff0c;直接看题&#xff1a; 下面是分析&#xff1a; (ab)%c(a%cb%c)%c; (a*b)%c(a%c*b%c)%c; 因此&#xff0c;如果两个长度不一样的值%m为相同值&#xff0c;那就舍弃长的&#xff08;因为再加1位只不过是原来值*10那位值&#xff0c;因此他们得出的%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单片机实现无线通信 无线发射主要运用到了三个知识点&#xff1a;EV1527格式&#xff1b;OOk&#xff1b;433MHZ。下面我们来分别阐述&#xff1a; EV1527是数据的编…...

Redis的过期键的删除策略

我们都知道&#xff0c;Redis是key-value数据库&#xff0c;我们可以设置Redis中缓存的key的过期时间。Redis的过期策略就是指当Redis中缓存的key过期了&#xff0c;Redis如何处理。 过期策略通常有以下三种&#xff1a; 定时过期&#xff1a;每个设置过期时间的key都需要创建…...

放假--寒假自学版 day1(补2.5)

fread 函数&#xff1a; 今日练习 C语言面试题5道~ 1. static 有什么用途&#xff1f;&#xff08;请至少说明两种&#xff09; 1) 限制变量的作用域 2) 设置变量的存储域 2. 引用与指针有什么区别&#xff1f; 1) 引用必须被初始化&#xff0c;指针不必。 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论文详解及项目实现

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

C++初阶:容器(Containers)vector常用接口详解

介绍完了string类的相关内容后&#xff1a;C初阶&#xff1a;适合新手的手撕string类&#xff08;模拟实现string类&#xff09; 接下来进入新的篇章&#xff0c;容器vector介绍&#xff1a; 文章目录 1.vector的初步介绍2.vector的定义&#xff08;constructor&#xff09;3.v…...

flink写入es的参数解析

ElasticsearchSink内部使用BulkProcessor一次将一批动作(ActionRequest)发送到ES集群。在发送批量动作前&#xff0c;BulkProcessor先缓存&#xff0c;再刷新。缓存刷新的间隔&#xff0c;支持基于Action数量、基于Action大小、基于时间间隔3种策略。BulkProcessor支持在同一次…...

逆向工程:揭开科技神秘面纱的艺术

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

决策树的相关知识点

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

【数据结构】单向链表实现 超详细

目录 一. 单链表的实现 1.准备工作及其注意事项 1.1 先创建三个文件 1.2 注意事项&#xff1a;帮助高效记忆和理解 2.链表的基本功能接口 2.0 创建一个 链表 2.1 链表的打印 3.链表的创建新节点接口 4.链表的节点插入功能接口 4.1 尾插接口 4.2 头插接口 4.3 指定位…...

Opencc4j 开源中文繁简体使用介绍

Opencc4j Opencc4j 支持中文繁简体转换&#xff0c;考虑到词组级别。 Features 特点 严格区分「一简对多繁」和「一简对多异」。 完全兼容异体字&#xff0c;可以实现动态替换。 严格审校一简对多繁词条&#xff0c;原则为「能分则不合」。 词库和函数库完全分离&#xff0c…...

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…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...