Jetpack太香了,让开发效率提升了不少
作者:Jingle_zhang
第三方App使用
Jetpack等开源框架非常流行,在Gradle文件简单指定即可。然而ROM内置的系统App在源码环境下进行开发,与第三方App脱节严重,采用开源框架的情况并不常见。但如果系统App也集成了Jetpack或第三方框架,开发效率则会大大提高。
前言
系统App开发者,很少采用Jetpack 以及第三方框架的原因主要有几点:
-
导入麻烦:有的框架过于庞大,可能依赖的库比较多,编译文件的构建比较繁琐,没有gradle那么智能
-
功能单一:系统App注重功能性,业务逻辑较少,依赖庞大库文件的场景不多
-
license风险:引用第三方框架的话,需要特别声明license ,会尽量避免采用
但对于功能复杂,架构庞大的系统App而言,集成第三方框架显得尤为必要。比如Android系统里最核心的App SystemUI,就采用了知名的DI框架Dagger2 。Dagger2的引入使得功能庞杂的SystemUI管理各个依赖模块变得游刃有余。
SystemUI将Dagger2集成的方式给了我启发,探索和总结了Android 源码中如何配置Jetpack 以及第三方库,希望能够帮到大家。
源码编译说明
与Gradle不同,源码环境里的编译构建都是配置在.mk或者.bp文件里的,配置起来较为繁琐。
.bp文件::Android.bp是用来替换Android.mk的配置文件,它使用Blueprint框架来解析。Blueprint是生成、解析Android.bp的工具,是Soong的一部分。Soong则是专为Android编译而设计的工具,Blueprint只是解析文件的形式,而Soong则解释内容的含义,最终转换成Ninja文件。下文bp 就是指.bp的文件
**注意:**以下基于Android 11上进行的演示,Android 10及之前部分Jetpack框架没有集成进源码,需留意
gradle切换到bp
gradle和bp的对比
看一个使用aar和注解库的例子。
看一个AndroidStudio(以下简称AS)下build.gradle 文件里包的导入代码:
dependencies {implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'com.google.android.material:material:1.2.1'implementation 'androidx.constraintlayout:constraintlayout:2.0.1'//roomdef room_version = "2.3.0"implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version"
}
ROM环境里的编译依赖.bp 配置如下:
android_app {......static_libs: [ "androidx.appcompat_appcompat", "com.google.android.material_material", "androidx-constraintlayout_constraintlayout", "androidx.room_room-runtime", ],plugins: ["androidx.room_room-compiler-plugin"],......
}
导入关键字的差异
依赖文件里的导入关键字:
在AS和AOSP里面导入包的关键字有些差异,又分为两种情况。
| build.gradle | .bp | |
|---|---|---|
| 代码库 | implementation | static_libs |
| 注解使用的库 | annotationProcessor | plugins |
引入库文件(libs):比较常见。引入的方式有多种。下文会讲具体的几种方式。
引入注解库:比较流行,源码中使用比较繁琐,下文会重点讲解。
库文件的导入规则
眼尖的同学已经看出规律了
如:implementation ‘androidx.appcompat:appcompat:1.2.0’
bp 文件中:androidx.appcompat_appcompat,将“:” 改为 “”即可,不需要加版本号。其实就是group 与 name 中间用“”连接,基本上符合上述规则,当然也有特殊
注解库的导入规则
如今框架流行注解编程。
gradle 配置:annotationProcessor “androidx.room:room-compiler:$room_version”
bp 中就需要使用到plugins,对应配置plugins: [“androidx.room_room-compiler-plugin”]
根据jar 包的规则,那plugin 命名应该是“:” 改为 ”_" version+“-plugin” 。
SystemUI 使用Dagger2配置 plugins: [“dagger2-compiler-2.19”],所以命名规则并不是上文猜测的那样。
那如何确定Jetpack框架的名称呢?
确定Jetpack框架的名称
源码编译,所有的内容和都在源码中,都需要在源码环境中寻找。
以Room 为例
在prebuilts/sdk/current/androidx/Android.bp 配置了引入jar包 中有如下配置
android_library {name: "androidx.room_room-runtime",//名称......manifest: "manifests/androidx.room_room-runtime/AndroidManifest.xml",//配置manifaststatic_libs: [//两个room库文件,三个依赖的库文件"androidx.room_room-runtime-nodeps","androidx.room_room-common","androidx.sqlite_sqlite-framework","androidx.sqlite_sqlite","androidx.arch.core_core-runtime",],
}
插件配置在prebuilts/sdk/current/androidx/JavaPlugins.bp
java_plugin {name: "androidx.room_room-compiler-plugin",//名称static_libs: [//1个room库文件,1个依赖的库文件"androidx.room_room-compiler","kotlin-reflect"],processor_class: "androidx.room.RoomProcessor",//需要指定处理的类
}
注意:AS 开发 并不需要配置 “processor_class”,我反编译了room-compiler,找到了RoomProcessor.java.(AS 为什么不需要指定,我这里我就不研究了)
看下图,META-INF/services/javax.annotation.processing.Processor 文件中配置了RoomProcessor.java(就按照这个文件配置就可以了)

如何确定源码中哪些jetpack 库可以使用呢?
在Android.bp 中搜索,或者看androidx目录下包含了什么
prebuilts/sdk/current/androidx/m2repository/androidx$ ls

导入第三方的开源框架
以上讲的是引入Jetpack相关jar包,其他常见的是否包含呢?如Glide,它是不属于androidx 的
第三方库,Android 源码中整理就不算好了,使用比较乱。下面我梳理下
导入下载的jar包
大家最常用的,把 jar 包 放到 libs,就可以了(当然,比较简单,与其他库关联较少可以采用此种方式)
java_import {name: "disklrucache-jar",jars: ["disklrucache-4.12.0.jar"],sdk_version: "current",
}
android_library_import {name: "glide-4.12.0",aars: ["glide-4.12.0.aar"],sdk_version: "current",
}
android_library_import {name: "gifdecoder-4.12.0",aars: ["gifdecoder-4.12.0.aar",],sdk_version: "current",
}
android_library_import {name: "exifinterface-1.2.0",aars: ["exifinterface-1.2.0.aar",],sdk_version: "current",
}
android_app {......static_libs: ["disklrucache-jar","glide-4.12.0","gifdecoder-4.12.0","exifinterface-1.2.0"],
}
导入AOSP内置的jar包
常用第三方放在了prebuilts/tools/common/m2/repository/下面包含了很多库文件,如Glide,Okhttp,但比较尴尬的是,.bp文件并没有写好。应用需要自己编写,编写方式可以参考上文。
以后google应该会把 external 下 的整合到这个里面,可以关注下prebuilts/tools/common/m2/repository 中Android.bp文件的变化。
如:prebuilts/maven_repo/bumptech/Android.bp
java_import {name: "glide-prebuilt",jars: ["com/github/bumptech/glide/glide/4.8.0/glide-4.8.0.jar","com/github/bumptech/glide/disklrucache/4.8.0/disklrucache-4.8.0.jar","com/github/bumptech/glide/gifdecoder/4.8.0/gifdecoder-4.8.0.jar",],jetifier: true,notice: "LICENSE",
}
Android.bp 直接用"glide"了
static_libs: ["glide-prebuilt"],
导入jar包源码
external 下面 很多第三方库的源码,如Glide的源码,目录为external/glide/
android_library {name: "glide",srcs: ["library/src/**/*.java","third_party/disklrucache/src/**/*.java","third_party/gif_decoder/src/**/*.java","third_party/gif_encoder/src/**/*.java",],manifest: "library/src/main/AndroidManifest.xml",libs: ["android-support-core-ui","android-support-compat","volley",],static_libs: ["android-support-fragment",],sdk_version: "current",
}复制代码
App 的Android.bp 直接用"glide"了
static_libs: ["glide"],
以上三种方式都是引入 Android 中源码存在的。不存在怎么办,Android源码 不像 AS,连上网,配置下版本号就可以下载。
内置新的Jetpack框架
引入第三方库文件方式,方式一:aar包导入。就可以。但这里不讨论,找些复杂的,包含annotationProcessor(bp 中的plugin) 。Hilt 是 Google 相对较新的框架。
Hilt基于Dagger2开发,又针对Android进行了专属的DI优化。
所以在导入Dagger2和它的依赖文件之外还需要导入Hilt专属的一堆库和依赖文件。
1. 获取框架的库文件
一般来说AS里导入完毕的目录下即可获取到对应的库文件,路径一般在 :C:\Users\xxx.gradle\caches\modules-2\files-2.1\com.google.dagger\hilt-android
2. 确定额外的依赖文件
为什么需要额外的依赖文件?
完全依赖AS开发可能不知道,导入的包的同时可能引入其他的包。
如Hilt的是在dagger2基础上开发,当然会引入Dagger2,
使用注解,需要javax.annotation包。
Dagger2,javax.annotation 在Gradle 自动下载好的,非项目中明确配置的,我们称之为依赖包。
使用Gradle 自动下载,都会有pom 文件。“dependency”,表示需要依赖的jar 包,还包含了版本号等
如:hilt-android-2.28-alpha.pom
`<dependency>``<groupId>com.google.dagger</groupId>``<artifactId>dagger</artifactId>` //依赖的dagger2`<version>2.28</version>`//dagger2的版本
`</dependency>`
`<dependency>``<groupId>com.google.dagger</groupId>` `<artifactId>dagger-lint-aar</artifactId>``<version>2.28</version>`
`</dependency>`
`<dependency>``<groupId>com.google.code.findbugs</groupId>``<artifactId>jsr305</artifactId>``<version>3.0.1</version>`
`</dependency>`
......
3. 导入需要的依赖文件
比如SystemUI,已经导入了一些文件,只要导入剩余的文件即可。
一般常用的 源码中都是存在的,决定copy 之前,可以看下先源码中是否存在,存在可以考虑使用。
当然也有例外,如Hilt 我依赖的是源码中dagger2是2.19 版本,编译中报错,没有找到dagger2 中的class,反编译jar确实不存在,使用2.28 的dagger 版本,问题就解决了。所以说可能存在库文件版本较老的情况。
以下就是新增的文件夹,其中manifests 后文中有讲。
manifests/ repository/com/google/dagger/dagger-compiler/2.28/repository/com/google/dagger/dagger-producers/2.28/repository/com/google/dagger/dagger-spi/2.28/repository/com/google/dagger/dagger/2.28/repository/com/google/dagger/hilt-android-compiler/repository/com/google/dagger/hilt-android/
4. 编写最终的bp文件
这一步就是把依赖的包,关联起来,根据上文的 pom 文件。
- 配置dagger2 2.28 的jar
java_import {name: "dagger2-2.28",jars: ["repository/com/google/dagger/dagger/2.28/dagger-2.28.jar"],host_supported: true,}
- 配置 dagger2-compiler 2.28 的jar (annotationProcessor 依赖的jar包)
java_import_host {name: "dagger2-compiler-2.28-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar",],
}
- 配置dagger2 的 plugin (annotationProcessor)
java_plugin {name: "dagger2-compiler-2.28",static_libs: ["dagger2-compiler-2.28-import","jsr330",],processor_class: "dagger.internal.codegen.ComponentProcessor",generates_api: true,
}
- 配置 hilt 依赖的aar包
android_library_import {name: "hilt-2.82-nodeps",aars: ["repository/com/google/dagger/hilt-android/2.28-alpha/hilt-android-2.28-alpha.aar"],sdk_version: "current",apex_available: ["//apex_available:platform","//apex_available:anyapex",],min_sdk_version: "14",static_libs: ["dagger2-2.28","jsr305","androidx.activity_activity","androidx.annotation_annotation","androidx.fragment_fragment",],}
-
配置hilt 的包
android_library 表示 aar 包,所以必须要配置manifests ,在上文中多出的manifasts文件夹中 放的就是这个文件,AndroidManifest.xml来自hilt-android-2.28-alpha.aar 中
android_library {name: "hilt-2.82",manifest: "manifests/dagger.hilt.android/AndroidManifest.xml",static_libs: ["hilt-2.82-nodeps","dagger2-2.28"],......
}
- 配置 hilt-compiler 2.82 jar包
java_import_host {name: "hilt-compiler-2.82-import",jars: ["repository/com/google/dagger/dagger-compiler/2.28/dagger-compiler-2.28.jar","repository/com/google/dagger/dagger-producers/2.28/dagger-producers-2.28.jar","repository/com/google/dagger/dagger-spi/2.28/dagger-spi-2.28.jar","repository/com/google/dagger/dagger/2.28/dagger-2.28.jar","repository/com/google/guava/guava/25.1-jre/guava-25.1-jre.jar","repository/com/squareup/javapoet/1.11.1/javapoet-1.11.1.jar","repository/com/google/dagger/dagger-google-java-format/1.6/google-java-format-1.6-all-deps.jar","repository/com/google/dagger/hilt-android-compiler/2.28-alpha/hilt-android-compiler-2.28-alpha.jar","repository/javax/inject/javax.inject/1/javax.inject-1.jar"],
}
-
配置hilt的 plugin (annotationProcessor)
反编译查看需要配置的Processer

好吧,看到上图我傻眼了,11个。下文代码我只贴了一个,需要写11个,其他省略。
java_plugin {name: "hilt-compiler-2.82",static_libs: ["hilt-compiler-2.82-import","jsr330",],processor_class: "dagger.hilt.processor.internal.root.RootProcessor",generates_api: true,
}
- 项目中引用
`static_libs: [``"androidx-constraintlayout_constraintlayout",``"androidx.appcompat_appcompat",``"com.google.android.material_material",``"androidx.room_room-runtime",``"androidx.lifecycle_lifecycle-viewmodel",``"androidx.lifecycle_lifecycle-livedata",``"hilt-2.82",``"jsr330"``],``plugins: ["androidx.room_room-compiler-plugin",``"hilt-compiler-2.82",``"hilt-compiler-2.82-UninstallModulesProcessor",``"hilt-compiler-2.82-TestRootProcessor",``"hilt-compiler-2.82-DefineComponentProcessor",``"hilt-compiler-2.82-BindValueProcessor",``"hilt-compiler-2.82-CustomTestApplicationProcessor",``"hilt-compiler-2.82-AndroidEntryPointProcessor",``"hilt-compiler-2.82-AggregatedDepsProcessor",``"hilt-compiler-2.82-OriginatingElementProcessor",``"hilt-compiler-2.82-AliasOfProcessor",``"hilt-compiler-2.82-GeneratesRootInputProcessor",``],`
-
编译确认
编译失败了!看到报错,我的心也凉了。需要配置Gradle 插件。bp 可以配置Gradle插件?
看了下com/google/dagger/hilt-android-gradle-plugin/,但是并不清楚bp 怎么配置,在源码里,只知道一处:prebuilts/gradle-plugin/Android.bp,但并没有尝试成功。有兴趣的同学,可以研究下。
而且hilt-android-gradle-plugin 的jar包,依赖包 至少十几个。
public class MainActivity extends AppCompatActivity { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
public class MainFragment extends BaseFragment { ^ Expected @AndroidEntryPoint to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
public class AppApplication extends Application { ^ Expected @HiltAndroidApp to have a value. Did you forget to apply the Gradle Plugin? [Hilt] Processing did not complete. See error above for details.
虽然Hilt引入失败,但是整个过程我觉得有必要分享一下,给大家一些导入新框架的参考。
源码环境里集成开源框架的流程

常用开源框架的对照表
| build.gradle | Android.bp | AOSP源码位置 |
|---|---|---|
| androidx.appcompat:appcompat | androidx.appcompat_appcompat | /sdk/current/androidx/Android.bp |
| androidx.core:core | androidx.core_core | prebuilts/sdk/current/androidx/Android.bp |
| com.google.android.material:material | com.google.android.material_material | prebuilts/sdk/current/extras/material-design-x/Android.bp |
| androidx.constraintlayout:constraintlayout | androidx-constraintlayout_constraintlayout | prebuilts/sdk/current/extras/constraint-layout-x/Android.bp |
| androidx.lifecycle:lifecycle-livedata | androidx.lifecycle_lifecycle-livedata | prebuilts/sdk/current/androidx/Android.bp |
| androidx.lifecycle:lifecycle-viewmodel | androidx.lifecycle_lifecycle-viewmodel | prebuilts/sdk/current/androidx/Android.bp |
| androidx.recyclerview:recyclerview | androidx.recyclerview_recyclerview | prebuilts/sdk/current/androidx/Android.bp |
| androidx.annotation:annotation | androidx.annotation_annotation | prebuilts/sdk/current/androidx/Android.bp |
| androidx.viewpager2:viewpager2 | androidx.viewpager2_viewpager2 | prebuilts/sdk/current/androidx/Android.bp |
| androidx.room:room-runtime | androidx.room_room-runtime | prebuilts/sdk/current/androidx/Android.bp |
| glide | glide-prebuilt | prebuilts/maven_repo/bumptech/Android.bp |
| gson | gson-prebuilt-jar | prebuilts/tools/common/m2/Android.bp |
| Robolectric相关 | Robolectric相关 | prebuilts/tools/common/m2/robolectric.bp |
经验总结
1、build.gradle 需要配置 额外插件的,如hilt、databinding viewbinding 不建议使用源码编译。
2、建议使用 AOSP 源码 中 bp 已经配置好的。这样就可以直接使用了。
3、jetpack 包引入或者androidx 引入,建议先prebuilts/sdk/current/androidx 下寻找配置好的bp 文件
4、非androidx ,建议先在prebuilts/tools/common/m2下寻找寻找配置好的bp 文件
5、文章中的例子都是prebuilts目录下配置,项目中使用,也可以配置在项目中,都是可以的。
相关文章:
Jetpack太香了,让开发效率提升了不少
作者:Jingle_zhang 第三方App使用Jetpack等开源框架非常流行,在Gradle文件简单指定即可。然而ROM内置的系统App在源码环境下进行开发,与第三方App脱节严重,采用开源框架的情况并不常见。但如果系统App也集成了Jetpack或第三方框架…...
【软考中级信安】第四章--网络安全体系与网络安全模型
1.网络安全体系概述1.1 网络安全体系概念网络安全体系:是网络安全保障系统的最高层概念抽象,是由各种网络安全单元按照一定的规则组成的,共同实现网络安全的目标。1.2 网络安全体系特性整体性:网络安全单元按照一定规则࿰…...
四、GC分析内存调优
文章目录(持续更新中... ...)GC分析&内存调优工具篇JDK自带的工具jconsolejvisualvm第三方工具arthas(重要)jprofiler(收费的)MAT、GChisto、gcviewer、GC Easy(待完善)参数、命…...
如何快速开发一套分布式IM系统
架构说明: 1)CIM 中的各个组件均采用 SpringBoot 构建;2)采用 Netty Google Protocol Buffer 构建底层通信;3)Redis 存放各个客户端的路由信息、账号信息、在线状态等;4)Zookeeper …...
W806|CKLINK LITE|调试|elf文件模板|CSDK|Debug|学习(4):CKLINK调试W806
一、硬件连接 接线方式 (连线颜色供参考,本例中采用图示颜色): 注意:CKLINK LITE的3V3须与W806的3V3相连,或者给W806开发板单独供电,两种方式均可。 否则,会提示“the referenc…...
【100个 Unity实用技能】 ☀️ | 脚本无需挂载到游戏对象上也可执行的方法
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案ÿ…...
「IT女神勋章」挑战赛#
缓存 本地缓存 本地缓存为了保证线程安全问题,一般使用ConcurrentMap的方式保存在内存之中 分布式缓存。 常见的分布式缓存则有Redis,MongoDB等。 一致性:本地缓存由于数据存储于内存之中,每个实例都有自己的副本,…...
易优cms user 登录注册标签
user 登录注册标签 user 登录注册入口标签 [基础用法] 标签:user 描述:动态显示购物车、登录、注册、退出、会员中心的入口; 用法: {eyou:user typeuserinfo} <div id"{$field.htmlid}"> …...
源码安装Redis 7.0.9并且systemctl管理
以下是在/usr/local/redis中通过源代码安装Redis 7.0.9并将其加入systemctl管理的步骤: 首先,下载Redis 7.0.9源代码包: wget https://download.redis.io/releases/redis-7.0.9.tar.gz解压缩Redis源代码包: tar xzf redis-7.0.9…...
编写程序:有92号和95号汽油可以选择,选择你需要的汽油,并输入需要加油的升数,点击按钮“`计算总价钱`“在div中可以得到你所需要支付的价格
需求: 有92号汽油和95号可以选择,选择你需要的汽油,并输入需要加油的升数,点击按钮"计算总价钱"在div中可以得到你所需要支付的价格。结构如下图所示: 详细代码如下: <!DOCTYPE html> &l…...
参考文献去哪里查找,参考文献标准格式是什么
1、参考文献类型: 普通图书[M]、期刊文章[J]、报纸文章[N]、论文集[C]、学位论 文[D]、报告[R]、标准[s]、专利[P]、数据库[DB]、计算机程序[CP]、电 子公告[EB]、联机网络[OL]、网上期刊[J/OL]、网上电子公告[EB/OL]、其他未 说明文献[z]。…...
WIFI标签操作步骤
1. 打开并设置手机WIFI热点,设置SSID为ESL,密码为123456789(如下图) 2. 运行APP,设置要接入的WIFI名称密码等信息(如下图) 3. 长按背面按键(长按2-3秒),…...
【Hello Linux】命令行解释器
作者:小萌新 专栏:Linux 作者简介:大二学生 希望能和大家一起进步! 本篇博客简介:使用进程的基础知识和进程控制知识做出一个简单的shell程序 命令行解释器介绍搭架子缓冲区获取命令如何从标准输入中获取字符串解析命令…...
开源一个通用的 HTTP 请求前端组件
像 Postman 这样可视化的 HTTP 请求工具是调试 API 不可或缺的利器。Postman 虽好但也越来越重,而且如果要整合到其他工具中,显然 Postman 又不是一个可行的方案。于是我想打造一个简单的前端组件(widget),它是一个标准…...
等保测评机构资质申请条件是什么?个人可以申请吗?
最近看到不少网友在问,等保测评机构资质申请条件是什么?个人可以申请吗?今天我们小编就来给大家详细回答一下。 等保测评机构资质申请条件是什么?个人可以申请吗? 【回答】:首先需要明确一点的是…...
android 卡顿、ANR优化(1)屏幕刷新机制
前言: 本文通过阅读各种文章和源码总结出来的,如有不对,还望指出 目录 正文 基础概念 视觉暂留 逐行扫描 帧 CPU/GPU/Surface: 帧率、刷新率、画面撕裂 画面撕裂 Android屏幕刷新机制的演变 单缓存(And…...
Landsat8中*_MTL.txt文件详解
01 什么是*_MTL.txt文件?所有的Landsat8 1级数据产品中均包含MTL.txt(Metadata File)文件。Landsat MTL文件包含对数据的系统搜索和归档分类有益的信息。该文件还包含关于数据处理和恶对增强陆地卫星数据有重要价值的信息(例如转换为反射率和辐射亮度&am…...
好的提高代码质量的方法有哪些?有什么经验和技巧?
用于确保代码质量的6个高层策略: 1 编写易于理解的代码 考虑如下这段文本。我们有意地使其变得难以理解,因此,不要浪费太多时间去解读。粗略地读一遍,尽可能吸收其中的内容。 〓ts〓取一个碗,我们现在称之为A。取一…...
yum保留安装包
一. 用downloadonly下载 1.1 处理依赖关系自动下载到/tmp/pages目录,pages这个目录会自动创建 yum install --downloadonly --downloaddir/tmp/pages ceph-deploy注意,如果下载的包包含了任何没有满足的依赖关系,yum将会把所有的依赖关系包下…...
ERP系统哪家比较好?
ERP系统哪家好?在选择ERP系统时,我们可以按照这三个维度,然后再按照需求去选择ERP系统。 市面上ERP软件大概可以分为三大类: ① 标准ERP应用:功能比较固定,难以满足个性化需求,二次开发难度很高…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
