Android Studio 自定義Gradle Plugin

一、簡介


之前公司的一個項目需要用到Gradle插件來修改編譯后的class文件,今天有時間就拿出來整理一下,學習一下Gradle插件的編寫還是一件十分有意義的事。



二、Gradle插件類型


  • 一種是直接在項目中的gradle文件里編寫,這種方式的缺點是無法復用插件代碼,在其他項目中還得復制一遍代碼(或者說說復制一遍文件)

  • 另一種是在獨立的項目里編寫插件,然后發布到中央倉庫,之后直接引用就可以了,優點就是可復用。

今天我們主要來講解下第二種。


三、Gradle插件


Gradle插件是使用Groovy進行開發的,而Groovy其實是可以兼容Java的。Android Studio其實除了開發Android App外,完全可以勝任開發Gradle插件這一工作。

在此之前我們先來了解下 Gradle插件Gradle 的關系:

Gradle插件 版本在項目根目錄下的 build.gradle 中,如下:

dependencies {classpath 'com.android.tools.build:gradle:2.3.0'
}

而每個Gradle插件版本號又對應有一個或一些 Gradle發行版本(一般是限定一個最低版本),也就是我們常見的類似gradle-3.3-all.zip這種東西,如下:

distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

如果這兩個版本對應不上了,那你的工程構建的時候就會報錯。

具體的對應關系如下:

插件版本所需的 Gradle 版本
1.0.0 - 1.1.32.2.1 - 2.3
1.2.0 - 1.3.12.2.1 - 2.9
1.5.02.2.1 - 2.13
2.0.0 - 2.1.22.10 - 2.13
2.1.3 - 2.2.32.14.1+
2.3.0+3.3+
3.0.0+4.1+
3.1.0+4.4+
3.2.0 - 3.2.14.6+
3.3.0 - 3.3.34.10.1+
3.4.0 - 3.4.35.1.1+
3.5.0 - 3.5.45.4.1+
3.6.0 - 3.6.45.6.4+
4.0.0+6.1.1+
4.1.0+6.5+

詳情請見:Android Gradle 插件版本說明


下面來講講具體如何開發。


1、創建插件步驟

第一步:新建一個Android工程

第二步:在該工程中新建一個Android Module項目,類型選擇Android Library
在這里插入圖片描述
第三步:將Module里的內容刪除,只保留build.gradle文件和src/main目錄,同時移除build.gradle文件里的內容

第四步:建立Gradle插件目錄

由于gradle是基于groovy,因此,我們開發的gradle插件相當于一個groovy項目。所以需要在main目錄下新建groovy目錄,這時候groovy文件夾會被Android識別為groovy源碼目錄。除了在main目錄下新建groovy目錄外,你還要在main目錄下新建resources目錄,同理resources目錄會被自動識別為資源文件夾。在groovy目錄下新建項目包名,就像Java包名那樣。resources目錄下新建文件夾META-INFMETA-INF文件夾下新建gradle-plugins文件夾。這樣,就完成了gradle 插件的項目的整體搭建。目前項目的結構是這樣的:
在這里插入圖片描述

第五步:修改build.gradle文件

內容如下:

apply plugin: 'groovy'
apply plugin: 'maven'dependencies{// gradle sdkcompile gradleApi()// groovy sdkcompile localGroovy()compile 'com.android.tools.build:gradle:1.5.0'
}repositories{mavenCentral()
}

第六步:在com.davisplugins包名下通過new -> file ->創建PluginImpl.groovy文件

內容如下:

package com.davispluginsimport com.android.build.gradle.AppExtension
import org.gradle.api.Plugin
import org.gradle.api.Projectpublic class PluginImpl implements Plugin<Project>{void apply(Project project){System.out.println("========================");System.out.println("hello gradle plugin!");System.out.println("========================");}
}

第七步:定義插件名稱

resources/META-INF/gradle-plugins目錄下新建一個properties文件,注意該文件的命名就是你使用插件的名字,這里命名為davis.properties,那么你在其他build.gradle文件中使用自定義的插件時候則需寫成:

apply plugin: 'davis'

davis.properties文件內容:

implementation-class=com.davisplugins.PluginImpl

注意包名需要替換為你自己的包名。

現在你的目錄結構如下:
在這里插入圖片描述

2、插件發布

前面我們已經自定義好了插件,接下來就是要打包到Maven庫里面去了,你可以選擇打包到本地,或者是遠程服務器中。

(1)打包到本地Maven倉庫

在我們自定義Module目錄下的build.gradle添加如下代碼:

uploadArchives {repositories {mavenDeployer {pom.groupId = 'com.davisplugins'pom.artifactId = 'davis'pom.version = 1.0// maven本地倉庫的目錄repository(url: uri('../DavisPlugin'))}}
}

這時候,右側的gradle Toolbar就會在module下多出一個task
在這里插入圖片描述
點擊uploadArchives這個Task,就會在項目下多出一個DavisPlugin目錄,里面存著這個gradle插件。
在這里插入圖片描述

(2)發布到遠程Jcenter倉庫

內容更新中…

3、插件的使用

我們來看下,發布到本地maven倉庫的插件如何使用,在項目根目錄下的gradle.build的文件中加入:

buildscript {repositories {// maven插件目錄maven{url uri('DavisPlugin')}jcenter()}dependencies {classpath 'com.android.tools.build:gradle:2.1.0'// 使用自定義插件classpath 'com.davisplugins:davis:1.0'}
}allprojects {repositories {jcenter()}
}task clean(type: Delete) {delete rootProject.buildDir
}

app目錄下的build.gradle文件中加入:

apply plugin: 'davis'

然后我們就可以使用該插件了,執行一次打包命令看看會發生啥吧!
在這里插入圖片描述
在打包之前輸出了我們打印的日志信息。

4、最佳實踐

(1)修改編譯后的class文件

我們回到如何修改class文件,首先我們得知道什么時候編譯完成,并且我們要趕在class文件被轉化為dex文件之前去修改。從1.5.0-beta1開始,android的gradle插件引入了com.android.build.api.transform.Transform,可以點擊 http://tools.android.com/tech-docs/new-build-system/transform-api 查看相關內容。Transform每次都是將一個輸入進行處理,然后將處理結果輸出,而輸出的結果將會作為另一個Transform的輸入,過程如下:
在這里插入圖片描述
注意:輸出地址不是由你任意指定的。而是根據輸入的內容、作用范圍等由TransformOutputProvider生成,比如,你要獲取輸出路徑:

String dest = outputProvider.getContentLocation(directoryInput.name,directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)

Transform是一個抽象類,我們先自定義一個Transform,如下:

package com.davispluginsimport com.android.build.api.transform.*
import com.android.build.gradle.internal.pipeline.TransformManager
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FileUtilspublic class InsertTransform extends Transform {//設置我們自定義的Transform對應的Task名稱@OverrideString getName() {return "DavisPlugin"}//指定輸入的類型,通過這里設定,可以指定我們要處理的文件類型//這樣確保其他類型的文件不會傳入@OverrideSet<QualifiedContent.ContentType> getInputTypes() {return TransformManager.CONTENT_CLASS}//指定Transfrom的作用范圍@OverrideSet<QualifiedContent.Scope> getScopes() {return TransformManager.SCOPE_FULL_PROJECT}@Overrideboolean isIncremental() {return false}@Overridevoid transform(Context context, Collection<TransformInput> inputs,Collection<TransformInput> referencedInputs,TransformOutputProvider outputProvider,boolean isIncremental) throws IOException,TransformException, InterruptedException {}
}

看到函數transform,我們還沒有具體實現這個函數。這個函數就是具體如何處理輸入和輸出。可以運行一下看看,注意,這里的運行時直接編譯執行我們的apk,而不是像之前那樣直接rebuild,因為rebuild并沒有執行到編譯這一步。由于我們沒有實現transform這個函數,導致沒有輸出!使得整個過程中斷了!最終導致apk運行時找不到MainActivity,所以會報錯。接下來我們去實現以下這個函數,我們啥也不干,就是把輸入內容寫入到作為輸出內容,不做任何處理:

	@Overridevoid transform(Context context, Collection<TransformInput> inputs,Collection<TransformInput> referencedInputs,TransformOutputProvider outputProvider,boolean isIncremental) throws IOException, TransformException, InterruptedException {// Transform的inputs有兩種類型,一種是目錄,一種是jar包,要分開遍歷inputs.each { TransformInput input ->//對類型為“文件夾”的input進行遍歷input.directoryInputs.each { DirectoryInput directoryInput ->//文件夾里面包含的是我們手寫的類以及R.class、BuildConfig.class以及R$XXX.class等// 獲取output目錄def dest = outputProvider.getContentLocation(directoryInput.name,directoryInput.contentTypes, directoryInput.scopes,Format.DIRECTORY)//這里執行字節碼的注入,不操作字節碼的話也要將輸入路徑拷貝到輸出路徑FileUtils.copyDirectory(directoryInput.file, dest)}//對類型為jar文件的input進行遍歷input.jarInputs.each { JarInput jarInput ->//jar文件一般是第三方依賴庫jar文件// 重命名輸出文件(同目錄copyFile會沖突)def jarName = jarInput.namedef md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())if (jarName.endsWith(".jar")) {jarName = jarName.substring(0, jarName.length() - 4)}//生成輸出路徑 + md5Namedef dest = outputProvider.getContentLocation(jarName + md5Name,jarInput.contentTypes, jarInput.scopes, Format.JAR)//這里執行字節碼的注入,不操作字節碼的話也要將輸入路徑拷貝到輸出路徑FileUtils.copyFile(jarInput.file, dest)}}}

注意input的類型,分為“文件夾”和“jar文件”,”文件夾”里面的就是我們寫的類對應的class文件,jar文件一般為第三方庫。此時,能成功運行,但是這里我們沒有注入任何代碼。

Transform類我們實現了,那么如何調用的呢?調用方式如下:

public class PluginImpl implements Plugin<Project>{void apply(Project project){def android = project.extensions.findByType(AppExtension);android.registerTransform(new InsertTransform())}
}

(2)監控每一個Task任務執行

在我們的工程目錄中我們可以看到還有一個TaskListener.groovy類,內容如下:

package com.davispluginsimport org.gradle.BuildListener
import org.gradle.BuildResult
import org.gradle.api.Task
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.initialization.Settings
import org.gradle.api.invocation.Gradle
import org.gradle.api.tasks.TaskStatepublic class TaskListener implements TaskExecutionListener, BuildListener {private static final String TAG = "[DAVIS] ";/*** 此類可以監控每一個task的執行開始和結束,以及工程build的情況*/public TaskListener(){}@Overridevoid beforeExecute(Task task) {println(TAG + "task before : " + task.getName())}/*** 比如,我們要在packageRelease這個task任務執行完后,做一些操作,* 我們就可以在此方法中判斷* @param task* @param taskState*/@Overridevoid afterExecute(Task task, TaskState taskState) {println(TAG + "task after : " + task.getName())if(task.getName().equals("packageRelease")){//做自己的任務}}@Overridevoid buildFinished(BuildResult result) {//項目build完成之后,會調用此方法println(TAG + "build finished.")}@Overridevoid buildStarted(Gradle gradle) {println(TAG + "build started.")}@Overridevoid projectsEvaluated(Gradle gradle) {println(TAG + "project evaluated.")}@Overridevoid projectsLoaded(Gradle gradle) {println(TAG + "project loaded.")}@Overridevoid settingsEvaluated(Settings settings) {println(TAG + "setting evaluated.")}
}

調用方式:

public class PluginImpl implements Plugin<Project>{void apply(Project project){project.gradle.addListener(new TaskListener())}
}

這個類是做啥用的呢,此類可以用來監控每一個Task任務的執行情況,比如我們在打apk包的過程中,其實就是調用了一連串的Task任務。下面是我們在未使用插件的情況下打一個release包過程中Gradle Console輸出的日志:

Executing tasks: [:app:assembleRelease]Configuration on demand is an incubating feature.
Incremental java compilation is an incubating feature.
:app:preBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:checkReleaseManifest
:app:prepareReleaseDependencies
:app:compileReleaseAidl UP-TO-DATE
:app:compileReleaseRenderscript UP-TO-DATE
:app:generateReleaseBuildConfig UP-TO-DATE
:app:mergeReleaseShaders UP-TO-DATE
:app:compileReleaseShaders UP-TO-DATE
:app:generateReleaseAssets UP-TO-DATE
:app:mergeReleaseAssets UP-TO-DATE
:app:generateReleaseResValues UP-TO-DATE
:app:generateReleaseResources UP-TO-DATE
:app:mergeReleaseResources UP-TO-DATE
:app:processReleaseManifest UP-TO-DATE
:app:processReleaseResources UP-TO-DATE
:app:generateReleaseSources UP-TO-DATE
:app:incrementalReleaseJavaCompilationSafeguard UP-TO-DATE
:app:compileReleaseJavaWithJavac UP-TO-DATE
:app:compileReleaseNdk UP-TO-DATE
:app:compileReleaseSources UP-TO-DATE
:app:lintVitalRelease
:app:prePackageMarkerForRelease
:app:transformClassesWithDexForRelease
To run dex in process, the Gradle daemon needs a larger heap.
It currently has approximately 1365 MB.
For faster builds, increase the maximum heap size for the Gradle daemon to more than 2048 MB.
To do this set org.gradle.jvmargs=-Xmx2048M in the project gradle.properties.
For more information see https://docs.gradle.org/current/userguide/build_environment.html
:app:mergeReleaseJniLibFolders UP-TO-DATE
:app:transformNative_libsWithMergeJniLibsForRelease UP-TO-DATE
:app:processReleaseJavaRes UP-TO-DATE
:app:transformResourcesWithMergeJavaResForRelease UP-TO-DATE
:app:validateExternalOverrideSigning
:app:packageRelease UP-TO-DATE
:app:zipalignRelease UP-TO-DATE
:app:assembleReleaseBUILD SUCCESSFULTotal time: 5.557 secs

那么我們使用了該插件之后輸出的日志是怎樣的那,如下:

Executing tasks: [:app:assembleRelease]Configuration on demand is an incubating feature.
Incremental java compilation is an incubating feature.
[DAVIS] project evaluated.
:app:preBuild
[DAVIS] task before : preBuild
:app:preBuild UP-TO-DATE
[DAVIS] task after : preBuild
:app:preReleaseBuild
[DAVIS] task before : preReleaseBuild
:app:preReleaseBuild UP-TO-DATE
[DAVIS] task after : preReleaseBuild
:app:checkReleaseManifest
[DAVIS] task before : checkReleaseManifest
[DAVIS] task after : checkReleaseManifest
:app:prepareReleaseDependencies
[DAVIS] task before : prepareReleaseDependencies
[DAVIS] task after : prepareReleaseDependencies
:app:compileReleaseAidl
[DAVIS] task before : compileReleaseAidl
:app:compileReleaseAidl UP-TO-DATE
[DAVIS] task after : compileReleaseAidl
:app:compileReleaseRenderscript
[DAVIS] task before : compileReleaseRenderscript
:app:compileReleaseRenderscript UP-TO-DATE
[DAVIS] task after : compileReleaseRenderscript
:app:generateReleaseBuildConfig
[DAVIS] task before : generateReleaseBuildConfig
:app:generateReleaseBuildConfig UP-TO-DATE
[DAVIS] task after : generateReleaseBuildConfig
:app:mergeReleaseShaders
[DAVIS] task before : mergeReleaseShaders
:app:mergeReleaseShaders UP-TO-DATE
[DAVIS] task after : mergeReleaseShaders
:app:compileReleaseShaders
[DAVIS] task before : compileReleaseShaders
:app:compileReleaseShaders UP-TO-DATE
[DAVIS] task after : compileReleaseShaders
:app:generateReleaseAssets
[DAVIS] task before : generateReleaseAssets
:app:generateReleaseAssets UP-TO-DATE
[DAVIS] task after : generateReleaseAssets
:app:mergeReleaseAssets
[DAVIS] task before : mergeReleaseAssets
:app:mergeReleaseAssets UP-TO-DATE
[DAVIS] task after : mergeReleaseAssets
:app:generateReleaseResValues
[DAVIS] task before : generateReleaseResValues
:app:generateReleaseResValues UP-TO-DATE
[DAVIS] task after : generateReleaseResValues
:app:generateReleaseResources
[DAVIS] task before : generateReleaseResources
:app:generateReleaseResources UP-TO-DATE
[DAVIS] task after : generateReleaseResources
:app:mergeReleaseResources
[DAVIS] task before : mergeReleaseResources
:app:mergeReleaseResources UP-TO-DATE
[DAVIS] task after : mergeReleaseResources
:app:processReleaseManifest
[DAVIS] task before : processReleaseManifest
:app:processReleaseManifest UP-TO-DATE
[DAVIS] task after : processReleaseManifest
:app:processReleaseResources
[DAVIS] task before : processReleaseResources
:app:processReleaseResources UP-TO-DATE
[DAVIS] task after : processReleaseResources
:app:generateReleaseSources
[DAVIS] task before : generateReleaseSources
:app:generateReleaseSources UP-TO-DATE
[DAVIS] task after : generateReleaseSources
:app:incrementalReleaseJavaCompilationSafeguard
[DAVIS] task before : incrementalReleaseJavaCompilationSafeguard
:app:incrementalReleaseJavaCompilationSafeguard UP-TO-DATE
[DAVIS] task after : incrementalReleaseJavaCompilationSafeguard
:app:compileReleaseJavaWithJavac
[DAVIS] task before : compileReleaseJavaWithJavac
:app:compileReleaseJavaWithJavac UP-TO-DATE
[DAVIS] task after : compileReleaseJavaWithJavac
:app:compileReleaseNdk
[DAVIS] task before : compileReleaseNdk
:app:compileReleaseNdk UP-TO-DATE
[DAVIS] task after : compileReleaseNdk
:app:compileReleaseSources
[DAVIS] task before : compileReleaseSources
:app:compileReleaseSources UP-TO-DATE
[DAVIS] task after : compileReleaseSources
:app:lintVitalRelease
[DAVIS] task before : lintVitalRelease
[DAVIS] task after : lintVitalRelease
:app:prePackageMarkerForRelease
[DAVIS] task before : prePackageMarkerForRelease
[DAVIS] task after : prePackageMarkerForRelease
:app:transformClassesWithDavisPluginForRelease
[DAVIS] task before : transformClassesWithDavisPluginForRelease
:app:transformClassesWithDavisPluginForRelease UP-TO-DATE
[DAVIS] task after : transformClassesWithDavisPluginForRelease
:app:transformClassesWithDexForRelease
[DAVIS] task before : transformClassesWithDexForRelease
To run dex in process, the Gradle daemon needs a larger heap.
It currently has approximately 1365 MB.
For faster builds, increase the maximum heap size for the Gradle daemon to more than 2048 MB.
To do this set org.gradle.jvmargs=-Xmx2048M in the project gradle.properties.
For more information see https://docs.gradle.org/current/userguide/build_environment.html
[DAVIS] task after : transformClassesWithDexForRelease
:app:mergeReleaseJniLibFolders
[DAVIS] task before : mergeReleaseJniLibFolders
:app:mergeReleaseJniLibFolders UP-TO-DATE
[DAVIS] task after : mergeReleaseJniLibFolders
:app:transformNative_libsWithMergeJniLibsForRelease
[DAVIS] task before : transformNative_libsWithMergeJniLibsForRelease
:app:transformNative_libsWithMergeJniLibsForRelease UP-TO-DATE
[DAVIS] task after : transformNative_libsWithMergeJniLibsForRelease
:app:processReleaseJavaRes
[DAVIS] task before : processReleaseJavaRes
:app:processReleaseJavaRes UP-TO-DATE
[DAVIS] task after : processReleaseJavaRes
:app:transformResourcesWithMergeJavaResForRelease
[DAVIS] task before : transformResourcesWithMergeJavaResForRelease
:app:transformResourcesWithMergeJavaResForRelease UP-TO-DATE
[DAVIS] task after : transformResourcesWithMergeJavaResForRelease
:app:validateExternalOverrideSigning
[DAVIS] task before : validateExternalOverrideSigning
[DAVIS] task after : validateExternalOverrideSigning
:app:packageRelease
[DAVIS] task before : packageRelease
:app:packageRelease UP-TO-DATE
[DAVIS] task after : packageRelease
:app:zipalignRelease
[DAVIS] task before : zipalignRelease
:app:zipalignRelease UP-TO-DATE
[DAVIS] task after : zipalignRelease
:app:assembleRelease
[DAVIS] task before : assembleRelease
[DAVIS] task after : assembleReleaseBUILD SUCCESSFULTotal time: 3.6 secs
[DAVIS] build finished.

從上面的日志我們可以看出,我們可以在項目打包前、某個Task任務執行前或執行后以及整個項目打包完成后來做自己想做的事了。

GitHub源碼地址:https://github.com/881205wzs/GradlePluginDemo
源碼下載地址:https://download.csdn.net/download/wangzhongshun/11010210

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446937.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446937.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446937.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++創建臨時文件

命令 std::string original_backup_file std::tmpnam(nullptr);

Android Studio Gradle兩種更新方式

第一種、Android Studio自動更新 第一步&#xff1a;修改gradle版本 修改項目根目錄/gradle/wrapper/gradle-wrapper.properties最后一行的地址&#xff1a; distributionUrlhttps://services.gradle.org/distributions/gradle-3.3-all.zip新gradle地址從官方下載的地方有。…

C++使用openssl實現aes加解密,其中加密是string到文件,解密是文件到string,切合項目背景

代碼 使用md5對于用戶輸入的密碼進行保護,也使得密碼的長度固定crypto_util.h#pragma once#include <string>namespace hsm{ namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]);void aes_encrypt_to_file(const std::string &fi…

Android Canvas的drawText()和文字居中方案

自定義View是繪制文本有三類方法&#xff1a; // 第一類 public void drawText (String text, float x, float y, Paint paint) public void drawText (String text, int start, int end, float x, float y, Paint paint) public void drawText (CharSequence text, int start…

IntelliJ IDEA配置Tomcat

查找該問題的童鞋我相信IntelliJ IDEA&#xff0c;Tomcat的下載&#xff0c;JDK等其他的配置都應該完成了&#xff0c;那我直接進入正題了。 1、新建一個項目 2、由于這里我們僅僅為了展示如何成功部署Tomcat&#xff0c;以及配置完成后成功運行一個jsp文件&#xff0c;我僅勾…

C++對于文件的相關操作 創建、讀寫、刪除代碼

創建 /*** brief 創建文件:在密碼設備內部創建用于存儲用戶數據的文件* param pucFileName 緩沖區指針&#xff0c;用于存放輸入的文件名&#xff0c;最大長度128字節* param uiNameLen 文件名長度* param uiFileSize 文件所占存儲空間的長度*/void CreateFile(sdf_uint8_t…

Android開發之Path詳解

目錄一、xxxTo方法1、lineTo(float x, float y)2、moveTo(float x, float y)3、arcTo3.1、arcTo(RectF oval, float startAngle, float sweepAngle)3.2、arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)3.3、arcTo(float left, float top, float r…

git大文件拷貝代碼命令

git clone 鏈接 --recursive

Android APK打包流程

目錄一、概述二、打包流程1、打包資源文件&#xff0c;生成R.java文件2、處理aidl文件&#xff0c;生成相應的Java文件3、編譯項目源代碼&#xff0c;生成class文件4、轉換所有的class文件&#xff0c;生成classes.dex文件5、打包生成APK文件6、對APK文件進行簽名7、對簽名后的…

使用openssl,實現輸入和輸出都是字符串的類型,注意:輸入最好是16的倍數

頭文件crypto_util.h #pragma once#include <string>namespace hsm{namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]);std::string aes_encrypt_to_string(const std::string &string,const std::string &password);std::s…

Android Studio 安裝ASM插件

目錄一、安裝步驟1、Android Studio -> Preferences...2、Plugins -> Browse repositories...3、搜索ASM -> 選中要安裝的插件 -> 右側點擊Install4、安裝完后點擊Restart Android Studio5、Android Studio重啟后右側會有個ASM圖標6、找一個類右鍵 -> Show Byte…

使用openssl完成aes-cbc模式的數據加解密,輸入和輸出都是字符串的形式

代碼 #include <cstring> #include <memory>#include <openssl/aes.h> #include <openssl/md5.h>namespace hsm{namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]){MD5_CTX md5_ctx{};MD5_Init(&md5_ctx);MD5…

Android 網絡異常

目錄前言一、UnknownHostException1、網絡斷開驗證2、DNS 服務器意外掛掉驗證3、DNS 服務器故障驗證4、所需診斷信息二、ConnectTimeoutException三、SocketTimeoutException1、子錯誤 - 讀超時2、子錯誤 - SSL 握手超時3、子錯誤 - 未知原因四、HttpHostConnectException1、服…

Android ViewRoot、DecorViewWindow淺析

目錄簡介目錄1、VeiwRoot1.1、簡介1.2、特別注意2、DecorView2.1、定義2.2、作用2.3、特別說明3、Window4、Activity5、之間關系5.1、總結5.2、之間的關系簡介 DecorView為整個Window界面的最頂層View。DecorView只有一個子元素為LinearLayout。代表整個Window界面&#xff0c;…

Java集合Stream類

Java集合Stream類 ----按條件對集合進行過濾filter public class Test {public static void main(String[] args) {List<String>allnew ArrayList<>();all.add("ghjt");all.add("ghjiiii");Stream<String>streamall.stream();List<S…

使用openssl完成aes-ecb模式的數據加解密,輸入和輸出都是字符串類型

代碼 #include <cstring> #include <memory>#include <openssl/aes.h> #include <openssl/md5.h>namespace hsm{namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]){MD5_CTX md5_ctx{};MD5_Init(&md5_ctx);MD5…

Java Stream MapReduce大數據開發模型

實現一個購買商品后,對數據進行處理統計的功能. 將購買的商品信息保存在Orders類中 public class Orders {private String name;private double price;private int amount;public Orders(String name, double price, int amount) {this.name name;this.price price;this.am…

隨機函數的生成

函數代碼 #include <string>bool GenerateRandom(std::string *str,unsigned int len) {srand(time(NULL));for(unsigned int i0;i<len;i){switch(rand()%3){case 1:(*str).push_back(Arand()%26);break;case 2:(*str).push_back(arand()%26);break;default:(*str).p…

Android 為控件設置陰影

在Android中設置一個陰影很簡單&#xff0c;只需要兩步&#xff1a; 設置eleavation值&#xff08;高度&#xff09;添加一個背景或者outline &#xff08;即陰影的形狀&#xff09; 說明&#xff1a; View的大小位置都是通過x&#xff0c;y確定的&#xff0c;而現在有了z軸的…

Android在代碼中設置drawableLeft(Right/Top/Bottom)

根據業務的需要&#xff0c;要在代碼中設置控件的drawableLeft&#xff0c;drawableRight&#xff0c;drawableTop&#xff0c;drawableBottom屬性。 我們知道在xml中設置的方法為&#xff1a; android:drawableLeft"drawable/xxxxx"但是在代碼中并沒有相關的setDr…