├── .gitignore
├── LICENSE
├── README.md
├── app-lib
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── libs
│ └── string-1.1.2.jar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── github
│ │ └── applib
│ │ └── Lib.java
│ └── res
│ └── values
│ └── strings.xml
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── lib.jar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── com
│ │ └── github
│ │ └── server
│ │ └── ITestInterface.aidl
│ ├── java
│ └── com
│ │ └── github
│ │ └── boxapp
│ │ ├── App.java
│ │ ├── DecryptionUtil.java
│ │ ├── MainActivity.java
│ │ └── StringPool.java
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── server
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── github
│ │ └── server
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ │ └── com
│ │ │ └── github
│ │ │ └── server
│ │ │ └── ITestInterface.aidl
│ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── server
│ │ │ ├── MainActivity.java
│ │ │ └── StringCipherService.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── github
│ └── server
│ └── ExampleUnitTest.java
├── settings.gradle
├── string-box
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── github
│ └── box
│ ├── StringCipher.java
│ ├── XxVv.java
│ ├── factory
│ └── StringCipherFactory.java
│ ├── impl
│ ├── AesStringCipher.java
│ ├── Base64StringCipher.java
│ ├── HexStringCipher.java
│ └── XorStringCipher.java
│ └── util
│ └── CipherUtil.java
└── string-plugin
├── build.gradle
└── src
└── main
├── groovy
└── com
│ └── github
│ └── box
│ └── EncryptionPlugin.groovy
├── java
└── com
│ └── github
│ └── box
│ ├── InjectClassVisitor.java
│ ├── InjectMethodVisitor.java
│ ├── PluginConfig.java
│ └── TextUtil.java
└── resources
└── META-INF
└── gradle-plugins
└── encryption.properties
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 | /.idea/
67 | /gradle/
68 | /gradlew.bat
69 | /gradlew
70 | /gradle.properties
71 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## box 1.1.5
2 | ### 一款对android项目中的字符串进行加密的gradle插件
3 | 项目基于TransformApi和Gradle Plugin,支持`gradle1.5.0`及以上版本
4 |
5 | 插件Groovy 依赖路径为:`com.github.box:plugin:1.1.5`
6 |
7 | 加解密库Groovy 依赖路径为:`com.github.box:string:1.1.2`
8 |
9 | 插件名称:`encryption `
10 |
11 | ### 集成方式
12 | #### 项目已经上传到jcenter,通过gradle 插件集成
13 | 在项目的根目录`build.gradle`中添加插件依赖
14 |
15 | ```
16 | dependencies {
17 | classpath 'com.android.tools.build:gradle:3.5.3'
18 | // 插件路径
19 | classpath "com.github.box:plugin:1.1.5"
20 | // NOTE: Do not place your application dependencies here; they belong
21 | // in the individual module build.gradle files
22 | }
23 | ```
24 |
25 | #### Application 以及 Module 集成
26 | **需要注意的是:插件自1.1.2版本开始,不再默认添加插件Lib的构件时依赖,需要开发者在项目中手动添加Lib的依赖**
27 |
28 | 在待集成模块的`build.gradle`中引入插件,添加Lib依赖
29 |
30 | ```
31 | apply plugin: 'encryption'
32 | ...
33 | implementation 'com.github.box:string:1.1.2'
34 | ```
35 |
36 |
37 | #### sdk集成
38 | 在待集成模块的`build.gradle`中引入插件
39 |
40 | ```
41 | apply plugin: 'encryption'
42 | ```
43 |
44 | 引入加解密Lib,有两种方式:
45 |
46 | 1. 显式通知app方集成Lib:
47 | ```
48 | implementation 'com.github.box:string:1.1.2'
49 | ```
50 |
51 | 需要注意的是,Lib版本应该与Plugin版本保持对应(目前Plugin版本1.1.5,Lib版本1.1.2)
52 |
53 | 2. 将加解密库文件Jar打包到SDK的`libs`中,添加运行时依赖:
54 |
55 | ```
56 | implementation files('libs/string-1.1.2.jar')
57 |
58 | ```
59 |
60 | 文件位置:项目目录`app-lib/libs`中。具体集成方式可以参照项目中module `app-lib` 的集成方式
61 |
62 | 如果自己定义了解密方法,可以不用依赖加解密jar包
63 |
64 | #### 插件支持扩展配置
65 |
66 | ```
67 | stringExt {
68 | encType = "base64"
69 | include = ["com.github.boxapp.StringPool"]
70 | pkg = "com.github.boxapp.DecryptionUtil"
71 | method = "decode"
72 | logOpen = true
73 | }
74 | ```
75 |
76 |
77 |
78 | 配置说明:
79 |
80 | 字段 | 类型|说明
81 | ----|----|----
82 | encType|字符串|加密类型:目前支持:base64、hex、xor、aes
83 | exclude|字符数组|声明不参加加密的类名路径:startWith匹配规则
84 | include|字符数组|声明强制参与加密的类名路径:startWith匹配规则
85 | pkg|字符串|声明参与解密的类名:startWith规则(需要和method一起配置)
86 | method|字符串|声明参与解密的方法名:全等规则(需要和pkg一起配置)
87 | logOpen|布尔值|配置是否打印日志,日志级别为Error,(此为打包日志,不是运行时日志)
88 |
89 | > 需要注意的是pkg和method需要同时配置,若不满足,则会选择加解密jar中的默认类名
90 |
91 | ### 加密规则说明
92 | 1. Base64 编码采用的NO_WRAP模式,且解密方法是通过反射调用的`android.util.Base64`下的静态方法,所以不适用通用java项目(主要是因为java base64api 在android sdk api26 以后才支持)
93 | 2. Hex 16进制编码会将原始字符串的体积增倍,建议选择性使用
94 | 3. Xor 异或加密采用的8位随机秘钥,一次一密
95 | 4. Aes 加密采用的16位随机秘钥 和 16位随机IV,一次一密
96 |
97 | ### License
98 | ```
99 | Licensed under the Apache License, Version 2.0 (the "License");
100 | you may not use this file except in compliance with the License.
101 | You may obtain a copy of the License at
102 |
103 | http://www.apache.org/licenses/LICENSE-2.0
104 |
105 | Unless required by applicable law or agreed to in writing, software
106 | distributed under the License is distributed on an "AS IS" BASIS,
107 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
108 | See the License for the specific language governing permissions and
109 | limitations under the License.
110 | ```
--------------------------------------------------------------------------------
/app-lib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app-lib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'encryption'
3 |
4 | stringExt {
5 | encType = "base64"
6 | include = ["com.github.applib.Lib"]
7 | }
8 |
9 | android {
10 | compileSdkVersion 29
11 | buildToolsVersion "29.0.2"
12 |
13 | defaultConfig {
14 | minSdkVersion 19
15 | targetSdkVersion 29
16 | versionCode 1
17 | versionName "1.0"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 | implementation 'androidx.appcompat:appcompat:1.1.0'
31 | }
32 |
--------------------------------------------------------------------------------
/app-lib/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app-lib/consumer-rules.pro
--------------------------------------------------------------------------------
/app-lib/libs/string-1.1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app-lib/libs/string-1.1.2.jar
--------------------------------------------------------------------------------
/app-lib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app-lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app-lib/src/main/java/com/github/applib/Lib.java:
--------------------------------------------------------------------------------
1 | package com.github.applib;
2 |
3 | import android.util.Log;
4 |
5 | public class Lib {
6 |
7 | private static final String S = "final static string";
8 |
9 | public void print() {
10 | Log.e("wh", "S1=" + S);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app-lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | app-lib
3 |
4 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'encryption'
3 |
4 | stringExt {
5 | encType = "base64"
6 | pkg = "com.github.boxapp.DecryptionUtil"
7 | method = "decode"
8 | include = ["com.github.boxapp.StringPool"]
9 | logOpen = true
10 | }
11 |
12 | android {
13 | compileSdkVersion 29
14 | buildToolsVersion "29.0.2"
15 |
16 | defaultConfig {
17 | applicationId "com.github.app"
18 | minSdkVersion 19
19 | targetSdkVersion 29
20 | versionCode 1
21 | versionName "1.0"
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | def libVersion = rootProject.properties.get("lib")
32 | def libImpl = 'com.github.box:string:' + libVersion + "@jar"
33 |
34 | dependencies {
35 | implementation 'androidx.appcompat:appcompat:1.1.0'
36 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
37 | implementation files('libs/lib.jar')
38 | // implementation project(':string-box')
39 |
40 | // 当没有配置pkg时,需要手动添加该依赖
41 | implementation libImpl
42 |
43 | // implementation project(':app-lib')
44 | }
45 |
--------------------------------------------------------------------------------
/app/libs/lib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/libs/lib.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/aidl/com/github/server/ITestInterface.aidl:
--------------------------------------------------------------------------------
1 | // ITestInterface.aidl
2 | package com.github.server;
3 |
4 | // Declare any non-default types here with import statements
5 |
6 | interface ITestInterface {
7 | String romoteValue();
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/boxapp/App.java:
--------------------------------------------------------------------------------
1 | package com.github.boxapp;
2 |
3 | import android.app.Application;
4 | import com.github.applib.Lib;
5 |
6 | public class App extends Application {
7 |
8 | @Override
9 | public void onCreate() {
10 | super.onCreate();
11 | new Lib().print();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/boxapp/DecryptionUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.boxapp;
2 |
3 | import android.util.Base64;
4 |
5 | public class DecryptionUtil {
6 | public static String decode(String encryption) {
7 | return new String(Base64.decode(encryption, Base64.NO_WRAP));
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/boxapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.boxapp;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.ServiceConnection;
7 | import android.os.Bundle;
8 | import android.os.IBinder;
9 | import android.os.RemoteException;
10 | import android.util.Log;
11 | import android.view.View;
12 | import androidx.fragment.app.FragmentActivity;
13 | import com.github.server.ITestInterface;
14 |
15 | public class MainActivity extends FragmentActivity implements View.OnClickListener {
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_main);
21 |
22 | findViewById(R.id.base64).setOnClickListener(this);
23 | findViewById(R.id.hex).setOnClickListener(this);
24 | findViewById(R.id.xor).setOnClickListener(this);
25 | findViewById(R.id.aes).setOnClickListener(this);
26 | findViewById(R.id.aidl).setOnClickListener(this);
27 | }
28 |
29 | @Override
30 | protected void onResume() {
31 | super.onResume();
32 | new StringPool().print();
33 | }
34 |
35 | @Override public void onClick(View v) {
36 | switch (v.getId()) {
37 | //case R.id.base64:
38 | // Base64StringCipher base64 = new Base64StringCipher();
39 | // String ee = base64.ee("this is base64");
40 | // Log.e("cipher", "Base64加密:" + ee);
41 | // String dd = base64.dd(ee);
42 | // Log.e("cipher", "Base64解密:" + dd);
43 | // break;
44 | //case R.id.hex:
45 | // HexStringCipher hexStringCipher = new HexStringCipher();
46 | // String hex = hexStringCipher.ee("this is hex");
47 | // Log.e("cipher", "HEX加密:" + hex);
48 | // String hexString = hexStringCipher.dd(hex);
49 | // Log.e("cipher", "HEX解密:" + hexString);
50 | // break;
51 | //case R.id.xor:
52 | // XorStringCipher xor = new XorStringCipher();
53 | // String xorString = xor.ee("this is xor");
54 | // Log.e("cipher", "XOR加密:" + xorString);
55 | // String string = xor.dd(xorString);
56 | // Log.e("cipher", "XOR解密:" + string);
57 | //
58 | // break;
59 | //case R.id.aes:
60 | // AesStringCipher aes = new AesStringCipher();
61 | // String aesString = aes.ee("this is aes");
62 | // Log.e("cipher", "AES加密:" + aesString);
63 | // String aesDecrypt = aes.dd(aesString);
64 | // Log.e("cipher", "AES解密:" + aesDecrypt);
65 | //
66 | // break;
67 | case R.id.aidl:
68 | Intent intent = new Intent();
69 | intent.setAction("com.github.service.ACTION");
70 | ComponentName component =
71 | new ComponentName("com.github.server", "com.github.server.StringCipherService");
72 | intent.setComponent(component);
73 | Log.e("wh", "client ready to bind");
74 | bindService(intent, new Conn(), Context.BIND_AUTO_CREATE);
75 | default:
76 | break;
77 | }
78 | }
79 |
80 | static class Conn implements ServiceConnection {
81 |
82 | @Override public void onServiceConnected(ComponentName name, IBinder service) {
83 | ITestInterface remote = ITestInterface.Stub.asInterface(service);
84 | try {
85 | String value = remote.romoteValue();
86 | Log.e("wh", "value return from service: " + value);
87 | } catch (RemoteException e) {
88 | e.printStackTrace();
89 | }
90 | }
91 |
92 | @Override public void onServiceDisconnected(ComponentName name) {
93 |
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/github/boxapp/StringPool.java:
--------------------------------------------------------------------------------
1 | package com.github.boxapp;
2 |
3 | import android.util.Log;
4 |
5 |
6 | public class StringPool {
7 | private static final String S1 = "this is static final const variable";
8 |
9 | private static String S2 = "this is static const variable";
10 |
11 | static {
12 | Log.e("wh", "this is static block");
13 | }
14 |
15 | private final String S3 = "this is final const variable";
16 | private String S4 = "this is normal variable";
17 |
18 | {
19 | Log.e("wh", "normal block string");
20 | }
21 |
22 | public void print() {
23 | Log.e("wh", "S1=" + S1);
24 | Log.e("wh", "S2=" + S2);
25 | Log.e("wh", "S3=" + S3);
26 | Log.e("wh", "S4=" + S4);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
20 |
27 |
34 |
41 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Client
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenLocal()
4 | google()
5 | jcenter()
6 | }
7 | def pluginVersion = rootProject.properties.get("plugin")
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.1.0'
10 | classpath "com.github.box:plugin:" + pluginVersion
11 | }
12 | }
13 |
14 |
15 | // gtradle 2.1 以上的集成方式
16 | plugins {
17 | id "com.jfrog.bintray" version "1.8.4"
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | mavenLocal()
23 | google()
24 | jcenter()
25 |
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/server/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 29
5 | buildToolsVersion "29.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.github.server"
9 | minSdkVersion 19
10 | targetSdkVersion 29
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 |
28 | implementation 'androidx.appcompat:appcompat:1.1.0'
29 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
30 | testImplementation 'junit:junit:4.12'
31 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
32 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
33 | }
34 |
--------------------------------------------------------------------------------
/server/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/server/src/androidTest/java/com/github/server/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.github.server;
2 |
3 | import android.content.Context;
4 | import androidx.test.platform.app.InstrumentationRegistry;
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
23 |
24 | assertEquals("com.github.server", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/server/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/server/src/main/aidl/com/github/server/ITestInterface.aidl:
--------------------------------------------------------------------------------
1 | // ITestInterface.aidl
2 | package com.github.server;
3 |
4 | // Declare any non-default types here with import statements
5 |
6 | interface ITestInterface {
7 | String romoteValue();
8 | }
9 |
--------------------------------------------------------------------------------
/server/src/main/java/com/github/server/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.server;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import androidx.appcompat.app.AppCompatActivity;
7 |
8 | /**
9 | * @author lotty
10 | */
11 | public class MainActivity extends AppCompatActivity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 | }
18 |
19 | public void start(View view) {
20 | Intent intent = new Intent(this, StringCipherService.class);
21 | intent.setAction("com.github.service.ACTION");
22 | startService(intent);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/server/src/main/java/com/github/server/StringCipherService.java:
--------------------------------------------------------------------------------
1 | package com.github.server;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.os.RemoteException;
7 | import android.util.Log;
8 | import androidx.annotation.Nullable;
9 |
10 | /**
11 | * @author lotty
12 | */
13 | public class StringCipherService extends Service {
14 |
15 | @Override public void onCreate() {
16 | super.onCreate();
17 | Log.e("wh", "service create");
18 | }
19 |
20 | @Override public void onDestroy() {
21 | super.onDestroy();
22 | Log.e("wh", "service destroy");
23 | }
24 |
25 | @Nullable @Override public IBinder onBind(Intent intent) {
26 | Log.e("wh", "service onBind");
27 | return new ITestInterface.Stub() {
28 | @Override public String romoteValue() throws RemoteException {
29 | return "this is from service.";
30 | }
31 | };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/server/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/server/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/server/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/server/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lotty520/box/23d8eb8e98e144354ef4f6c49ced73bc041127c7/server/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/server/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/server/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Server
3 |
4 |
--------------------------------------------------------------------------------
/server/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/server/src/test/java/com/github/server/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.github.server;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':string-box', ':string-plugin', ':app-lib', ':server'
--------------------------------------------------------------------------------
/string-box/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/string-box/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: "maven-publish"
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 |
6 | //任务
7 | task javadocJar(type: Jar, dependsOn: javadoc) {
8 | archiveClassifier = 'javadoc'
9 | from 'build/docs/javadoc'
10 | }
11 |
12 | task sourcesJar(type: Jar) {
13 | archiveClassifier = 'sources'
14 | from sourceSets.main.allSource
15 | }
16 |
17 | // pom配置
18 | def pomConfig = {
19 | licenses {
20 | license {
21 | name "The Apache Software License, Version 2.0"
22 | url "http://www.apache.org/licenses/LICENSE-2.0.txt"
23 | distribution "repo"
24 | }
25 | }
26 | developers {
27 | developer {
28 | id "lotty"
29 | name "lotty-tj"
30 | email "wuh24.tj@gmail.com"
31 | }
32 | }
33 |
34 | scm {
35 | url "https://github.com/lotty520/box"
36 | }
37 | }
38 |
39 | def bintrayUser = rootProject.properties.get("bintray.user")
40 | def bintrayKey = rootProject.properties.get("bintray.apikey")
41 | def libVersion = rootProject.properties.get("lib.version")
42 |
43 | bintray {
44 | user = bintrayUser
45 | key = bintrayKey
46 | publications = ['stringBox']
47 | pkg {
48 | repo = 'maven'
49 | name = 'box'
50 | userOrg = 'lotty-tj'
51 | licenses = ['Apache-2.0']
52 | vcsUrl = 'https://github.com/lotty520/box.git'
53 | publish = true
54 | version {
55 | name = libVersion
56 | desc = 'java aop class inject library'
57 | released = new Date()
58 | }
59 | }
60 | }
61 |
62 | publishing {
63 | publications {
64 | stringBox(MavenPublication) {
65 | from components.java
66 | artifact sourcesJar
67 | artifact javadocJar
68 | groupId 'com.github.box'
69 | artifactId 'string'
70 | version libVersion
71 | pom.withXml {
72 | def root = asNode()
73 | root.appendNode('url', 'https://github.com/lotty520/box.git')
74 | root.children().last() + pomConfig
75 | }
76 | }
77 | }
78 | }
79 |
80 |
81 |
--------------------------------------------------------------------------------
/string-box/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | #是否压缩
2 | -dontshrink
3 | -dontoptimize
4 |
5 | -keepattributes SourceFile,LineNumberTable
6 | -keepattributes *Annotation*
7 | -keepattributes *JavascriptInterface*
8 | -keepattributes Exceptions
9 | -keepattributes Signature
10 | # If you keep the line number information, uncomment this to
11 | # hide the original source file name.
12 | -renamesourcefileattribute Posture
13 |
14 | -dontwarn android.os.**
15 | -dontwarn android.support.**
16 | -dontwarn com.android.internal.**
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/string-box/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/StringCipher.java:
--------------------------------------------------------------------------------
1 | package com.github.box;
2 |
3 | /**
4 | * @author lotty
5 | */
6 | public interface StringCipher {
7 |
8 | /**
9 | * 解密
10 | *
11 | * @param value 初始值
12 | * @param key Key
13 | * @param iv Iv
14 | * @return 解密结果
15 | */
16 | String dd(String value, String key, String iv);
17 |
18 | /**
19 | * 加密
20 | *
21 | * @param value 初始值
22 | * @param key Key
23 | * @param iv Iv
24 | * @return 加密结果
25 | */
26 | String ee(String value, String key, String iv);
27 | }
28 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/XxVv.java:
--------------------------------------------------------------------------------
1 | package com.github.box;
2 |
3 | import com.github.box.impl.AesStringCipher;
4 | import com.github.box.impl.Base64StringCipher;
5 | import com.github.box.impl.HexStringCipher;
6 | import com.github.box.impl.XorStringCipher;
7 |
8 | public class XxVv {
9 |
10 | /**
11 | * base64
12 | *
13 | * @param v 密文
14 | * @return 明文
15 | */
16 | public static String xr(String v) {
17 | return new Base64StringCipher().dd(v, null, null);
18 | }
19 |
20 | /**
21 | * hex
22 | *
23 | * @param v 密文
24 | * @return 明文
25 | */
26 | public static String rx(String v) {
27 | return new HexStringCipher().dd(v, null, null);
28 | }
29 |
30 | /**
31 | * aes
32 | *
33 | * @param v 密文
34 | * @param k Key
35 | * @param i Iv
36 | * @return 明文
37 | */
38 | public static String vv(String v, String k, String i) {
39 | return new AesStringCipher().dd(v, k, i);
40 | }
41 |
42 | /**
43 | * xor
44 | *
45 | * @param v 密文
46 | * @param k Key
47 | * @return 明文
48 | */
49 | public static String vx(String v, String k) {
50 | return new XorStringCipher().dd(v, k, null);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/factory/StringCipherFactory.java:
--------------------------------------------------------------------------------
1 | package com.github.box.factory;
2 |
3 | import com.github.box.StringCipher;
4 | import com.github.box.impl.AesStringCipher;
5 | import com.github.box.impl.Base64StringCipher;
6 | import com.github.box.impl.HexStringCipher;
7 | import com.github.box.impl.XorStringCipher;
8 |
9 | public class StringCipherFactory {
10 |
11 | private final static String TYPE_BASE64 = "base64";
12 | private final static String TYPE_XOR = "xor";
13 | private final static String TYPE_HEX = "hex";
14 | private final static String TYPE_AES = "aes";
15 |
16 | public static StringCipher create(String type) {
17 | if (TYPE_BASE64.equals(type)) {
18 | return new Base64StringCipher();
19 | } else if (TYPE_XOR.equals(type)) {
20 | return new XorStringCipher();
21 | } else if (TYPE_HEX.equals(type)) {
22 | return new HexStringCipher();
23 | } else if (TYPE_AES.equals(type)) {
24 | return new AesStringCipher();
25 | }
26 | return new Base64StringCipher();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/impl/AesStringCipher.java:
--------------------------------------------------------------------------------
1 | package com.github.box.impl;
2 |
3 | import com.github.box.StringCipher;
4 | import com.github.box.util.CipherUtil;
5 | import java.security.InvalidAlgorithmParameterException;
6 | import java.security.InvalidKeyException;
7 | import java.security.Key;
8 | import java.security.NoSuchAlgorithmException;
9 | import java.util.Base64;
10 | import javax.crypto.BadPaddingException;
11 | import javax.crypto.Cipher;
12 | import javax.crypto.IllegalBlockSizeException;
13 | import javax.crypto.NoSuchPaddingException;
14 | import javax.crypto.SecretKey;
15 | import javax.crypto.spec.IvParameterSpec;
16 | import javax.crypto.spec.SecretKeySpec;
17 |
18 | /**
19 | * @author lotty
20 | */
21 | public class AesStringCipher implements StringCipher {
22 |
23 | private static final String MODE = "AES/CBC/PKCS5Padding";
24 | private static final String CIPHER = "AES";
25 |
26 | @Override
27 | public String dd(String value, String k, String i) {
28 | SecretKey ks = new SecretKeySpec(k.getBytes(), CIPHER);
29 | IvParameterSpec iv = new IvParameterSpec(i.getBytes());
30 | try {
31 | Cipher cipher = Cipher.getInstance(MODE);
32 | cipher.init(Cipher.DECRYPT_MODE, ks, iv);
33 | byte[] bytes = CipherUtil.callAndroidBase64Decode(value);
34 | if (bytes != null) {
35 | return new String(cipher.doFinal(bytes));
36 | }
37 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | InvalidAlgorithmParameterException e) {
38 | e.printStackTrace();
39 | }
40 | return "";
41 | }
42 |
43 | @Override
44 | public String ee(String value, String k, String i) {
45 | Key ks = new SecretKeySpec(k.getBytes(), CIPHER);
46 | IvParameterSpec iv = new IvParameterSpec(i.getBytes());
47 | try {
48 | Cipher cipher = Cipher.getInstance(MODE);
49 | cipher.init(Cipher.ENCRYPT_MODE, ks, iv);
50 | byte[] b = cipher.doFinal(value.getBytes());
51 | return new String(Base64.getEncoder().encode(b));
52 | } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
53 | e.printStackTrace();
54 | }
55 | return "";
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/impl/Base64StringCipher.java:
--------------------------------------------------------------------------------
1 | package com.github.box.impl;
2 |
3 | import com.github.box.StringCipher;
4 | import com.github.box.util.CipherUtil;
5 |
6 | /**
7 | * @author lotty
8 | */
9 | public class Base64StringCipher implements StringCipher {
10 |
11 | @Override
12 | public String dd(String value, String k, String i) {
13 | byte[] bytes = CipherUtil.callAndroidBase64Decode(value);
14 | if (bytes != null) {
15 | return new String(bytes);
16 | }
17 | return "";
18 | }
19 |
20 | @Override
21 | public String ee(String value, String k, String i) {
22 | return new String(java.util.Base64.getEncoder().encode(value.getBytes()));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/impl/HexStringCipher.java:
--------------------------------------------------------------------------------
1 | package com.github.box.impl;
2 |
3 | import com.github.box.StringCipher;
4 |
5 | /**
6 | * @author lotty
7 | */
8 | public class HexStringCipher implements StringCipher {
9 | private final static String ZERO_STRING = "0";
10 | private final static String HEX_PREFIX = "0x";
11 |
12 | @Override
13 | public String dd(String value, String k, String iv) {
14 | int byteLen = value.length() / 2;
15 | byte[] ret = new byte[byteLen];
16 | for (int i = 0; i < byteLen; i++) {
17 | Integer intVal = Integer.decode(HEX_PREFIX + value.substring(i * 2, i * 2 + 2));
18 | ret[i] = intVal.byteValue();
19 | }
20 | return new String(ret);
21 | }
22 |
23 | @Override
24 | public String ee(String value, String k, String iv) {
25 | byte[] bytes = value.getBytes();
26 | StringBuilder sb = new StringBuilder();
27 | for (int i = 0; i < bytes.length; i++) {
28 | String hex = Integer.toHexString(bytes[i] & 0xFF);
29 | if (hex.length() == 1) {
30 | sb.append(ZERO_STRING);
31 | }
32 | sb.append(hex);
33 | }
34 | return sb.toString();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/impl/XorStringCipher.java:
--------------------------------------------------------------------------------
1 | package com.github.box.impl;
2 |
3 | import com.github.box.StringCipher;
4 | import com.github.box.util.CipherUtil;
5 | import java.util.Base64;
6 |
7 | /**
8 | * @author lotty
9 | */
10 | public class XorStringCipher implements StringCipher {
11 |
12 | @Override
13 | public String dd(String value, String k, String iv) {
14 | byte[] key = k.getBytes();
15 | byte[] data = CipherUtil.callAndroidBase64Decode(value);
16 | if (data != null) {
17 | byte[] result = new byte[data.length];
18 | for (int i = 0; i < data.length; i++) {
19 | result[i] = (byte) (data[i] ^ key[i % key.length]);
20 | }
21 | return new String(result);
22 | }
23 | return "";
24 | }
25 |
26 | @Override
27 | public String ee(String value, String k, String iv) {
28 | byte[] key = k.getBytes();
29 | byte[] data = value.getBytes();
30 | byte[] result = new byte[data.length];
31 | for (int i = 0; i < data.length; i++) {
32 | result[i] = (byte) (data[i] ^ key[i % key.length]);
33 | }
34 | return new String(Base64.getEncoder().encode(result));
35 | }
36 | }
--------------------------------------------------------------------------------
/string-box/src/main/java/com/github/box/util/CipherUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.box.util;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.lang.reflect.Method;
5 |
6 | /**
7 | * @author lotty
8 | */
9 | public class CipherUtil {
10 |
11 | private final static char[] CHARS = new char[] {
12 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
13 | 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
14 | 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '*', '&', '$', '#', '@',
15 | '!', '+', '-'
16 | };
17 |
18 | private CipherUtil() {
19 | }
20 |
21 | public static byte[] callAndroidBase64Decode(String value) {
22 | try {
23 | Class cls = Class.forName("android.util.Base64");
24 | Method method = cls.getDeclaredMethod("decode", String.class, int.class);
25 | return (byte[]) method.invoke(null, value, 2);
26 | } catch (ClassNotFoundException e) {
27 | e.printStackTrace();
28 | } catch (NoSuchMethodException e) {
29 | e.printStackTrace();
30 | } catch (IllegalAccessException e) {
31 | e.printStackTrace();
32 | } catch (InvocationTargetException e) {
33 | e.printStackTrace();
34 | }
35 | return null;
36 | }
37 |
38 | /**
39 | * 获取随机字符序列
40 | *
41 | * @param length 获取的长度
42 | * @return 结果
43 | */
44 | public static String randomString(int length) {
45 | StringBuilder builder = new StringBuilder();
46 | for (int i = 0; i < length; i++) {
47 | double random = Math.random();
48 | int index = (int) (random * CHARS.length);
49 | builder.append(CHARS[index]);
50 | }
51 | return builder.toString();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/string-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'groovy'
2 | apply plugin: "maven-publish"
3 | apply plugin: 'com.jfrog.bintray'
4 |
5 | //Groovy 编译选项
6 | compileGroovy {
7 | sourceCompatibility = 1.8
8 | targetCompatibility = 1.8
9 | options.encoding = "UTF-8"
10 | }
11 |
12 | //def libImpl = 'com.github.box:string:' + rootProject.properties.get("lib") + "@jar"
13 | def libImpl = 'com.github.box:string:1.1.2@jar'
14 | // 依赖
15 | dependencies {
16 | implementation gradleApi()
17 | implementation libImpl
18 | // implementation project(':string-box')
19 | implementation 'com.android.tools.build:gradle:3.1.0'
20 | }
21 |
22 | //任务
23 | task javadocJar(type: Jar, dependsOn: javadoc) {
24 | archiveClassifier = 'javadoc'
25 | from 'build/docs/javadoc'
26 | }
27 |
28 | task sourcesJar(type: Jar) {
29 | from sourceSets.main.allSource
30 | archiveClassifier = 'sources'
31 | }
32 |
33 | // pom配置
34 | def pomConfig = {
35 | licenses {
36 | license {
37 | name "The Apache Software License, Version 2.0"
38 | url "http://www.apache.org/licenses/LICENSE-2.0.txt"
39 | distribution "repo"
40 | }
41 | }
42 | developers {
43 | developer {
44 | id "lotty"
45 | name "lotty-tj"
46 | email "wuh24.tj@gmail.com"
47 | }
48 | }
49 |
50 | scm {
51 | url "https://github.com/lotty520/box"
52 | }
53 | }
54 |
55 | def bintrayUser = rootProject.properties.get("bintray.user")
56 | def bintrayKey = rootProject.properties.get("bintray.apikey")
57 | def pluginVersion = rootProject.properties.get("plugin.version")
58 |
59 | bintray {
60 | user = bintrayUser
61 | key = bintrayKey
62 | publications = ['stringPlugin']
63 | pkg {
64 | repo = 'maven'
65 | name = 'box'
66 | userOrg = 'lotty-tj'
67 | licenses = ['Apache-2.0']
68 | vcsUrl = 'https://github.com/lotty520/box.git'
69 | publish = true
70 | version {
71 | name = pluginVersion
72 | desc = 'java aop class inject plugin'
73 | released = new Date()
74 | }
75 | }
76 | }
77 |
78 |
79 | publishing {
80 | publications {
81 | stringPlugin(MavenPublication) {
82 | from components.java
83 | artifact sourcesJar
84 | artifact javadocJar
85 |
86 | groupId 'com.github.box'
87 | artifactId 'plugin'
88 | version pluginVersion
89 | pom.withXml {
90 | def root = asNode()
91 | root.appendNode('url', 'https://github.com/lotty520/box')
92 | root.children().last() + pomConfig
93 | }
94 | }
95 | }
96 | }
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/string-plugin/src/main/groovy/com/github/box/EncryptionPlugin.groovy:
--------------------------------------------------------------------------------
1 | package com.github.box
2 |
3 | import com.android.build.api.transform.*
4 | import com.android.build.gradle.AppExtension
5 | import com.android.build.gradle.AppPlugin
6 | import com.android.build.gradle.LibraryExtension
7 | import com.android.build.gradle.LibraryPlugin
8 | import com.android.build.gradle.internal.pipeline.TransformManager
9 | import org.apache.commons.io.FileUtils
10 | import org.apache.commons.io.IOUtils
11 | import org.gradle.api.Plugin
12 | import org.gradle.api.Project
13 | import org.objectweb.asm.ClassReader
14 | import org.objectweb.asm.ClassVisitor
15 | import org.objectweb.asm.ClassWriter
16 |
17 | import java.util.jar.JarEntry
18 | import java.util.jar.JarFile
19 | import java.util.jar.JarOutputStream
20 | import java.util.zip.ZipEntry
21 |
22 | class EncryptionPlugin extends Transform implements Plugin {
23 |
24 | def app
25 | def lib
26 |
27 | private final static String EXT = "stringExt"
28 |
29 | private Project mProject;
30 |
31 | @Override
32 | void apply(Project project) {
33 | println("=======================")
34 | println(" box插件 ")
35 | println("=======================")
36 |
37 | if (!project.android) {
38 | throw new IllegalStateException(
39 | 'Must apply \'com.android.application\' or \'com.android.library\' first!')
40 | }
41 | mProject = project
42 |
43 | app = project.plugins.withType(AppPlugin)
44 | lib = project.plugins.withType(LibraryPlugin)
45 | if (!app && !lib) {
46 | throw new IllegalStateException("'android' or 'android-library' plugin required.")
47 | }
48 | project.extensions.create(EXT, PluginConfig)
49 | if (app) {
50 | project.extensions.getByType(AppExtension).registerTransform(this)
51 | } else {
52 | project.extensions.getByType(LibraryExtension).registerTransform(this)
53 | }
54 | }
55 |
56 | @Override
57 | String getName() {
58 | return "encryption"
59 | }
60 |
61 | @Override
62 | Set getInputTypes() {
63 | return TransformManager.CONTENT_CLASS
64 | }
65 |
66 | @Override
67 | Set super QualifiedContent.Scope> getScopes() {
68 | if (lib) {
69 | return TransformManager.PROJECT_ONLY
70 | }
71 | return TransformManager.SCOPE_FULL_PROJECT
72 | }
73 |
74 | @Override
75 | boolean isIncremental() {
76 | return false
77 | }
78 |
79 | @Override
80 | void transform(TransformInvocation transformInvocation)
81 | throws TransformException, InterruptedException, IOException {
82 | println("==============================")
83 | println(" transform begin ")
84 | println("===============================")
85 | Collection inputs = transformInvocation.inputs
86 | TransformOutputProvider outputProvider = transformInvocation.outputProvider
87 |
88 | PluginConfig config = mProject.extensions.getByName(EXT)
89 | println("===============config below================")
90 | println("include: " + (config.include == null ? "[]" : config.include))
91 | println("encType: " + (config.encType == null ? "" : config.encType))
92 | println("pkg: " + (config.pkg == null ? "" : config.pkg))
93 | println("method: " + (config.method == null ? "" : config.method))
94 | println("logOpen: " + config.logOpen)
95 | //删除之前的输出
96 | if (outputProvider != null) {
97 | outputProvider.deleteAll()
98 | }
99 | //遍历inputs
100 | inputs.each { TransformInput input ->
101 | //遍历directoryInputs
102 | input.directoryInputs.each { DirectoryInput directoryInput ->
103 | handleDirectoryInput(directoryInput, outputProvider, config)
104 | }
105 |
106 | //遍历jarInputs
107 | input.jarInputs.each { JarInput jarInput ->
108 | handleJarInputs(jarInput, outputProvider, config)
109 | }
110 | }
111 | }
112 |
113 | /**
114 | * 处理文件目录下的class文件
115 | */
116 | private static void handleDirectoryInput(DirectoryInput directoryInput,
117 | TransformOutputProvider outputProvider, PluginConfig config) {
118 | //是否是目录
119 | if (directoryInput.file.isDirectory()) {
120 | //列出目录所有文件(包含子文件夹,子文件夹内文件)
121 | directoryInput.file.eachFileRecurse { File file ->
122 | def name = file.name
123 | if (file.isFile() && checkClassInDir(name, file.absolutePath, config)) {
124 | ClassReader classReader = new ClassReader(file.bytes)
125 | ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
126 | ClassVisitor cv = new InjectClassVisitor(classWriter, config)
127 | classReader.accept(cv, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG)
128 | byte[] code = classWriter.toByteArray()
129 | FileOutputStream writer = new FileOutputStream(file.absolutePath)
130 | //覆写
131 | writer.write(code)
132 | writer.close()
133 | }
134 | }
135 | }
136 | // 将注入完成的目录拷贝到编译的结果输出目录
137 | def dest = outputProvider.getContentLocation(directoryInput.name, directoryInput.contentTypes,
138 | directoryInput.scopes, Format.DIRECTORY)
139 | FileUtils.copyDirectory(directoryInput.file, dest)
140 | }
141 |
142 | /**
143 | * 处理Jar中的class文件
144 | */
145 | private static void handleJarInputs(JarInput jarInput, TransformOutputProvider outputProvider,
146 | PluginConfig config) {
147 | if (jarInput.file.getAbsolutePath().endsWith(".jar")) {
148 | // 创建新的jar文件
149 | File jar = new File(jarInput.file.getParent() + File.separator +
150 | "classes_posture" +
151 | System.currentTimeMillis() +
152 | ".jar")
153 | //避免上次的缓存被重复插入
154 | if (jar.exists()) {
155 | jar.delete()
156 | }
157 | JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jar))
158 | //用于保存
159 | JarFile originJar = new JarFile(jarInput.file)
160 | Enumeration enumeration = originJar.entries()
161 | while (enumeration.hasMoreElements()) {
162 | JarEntry inEntry = (JarEntry) enumeration.nextElement()
163 | //名称
164 | String name = inEntry.getName()
165 | //创建zipEntry对象
166 | ZipEntry outEntry = new ZipEntry(name)
167 | //获取当前entry的输入流
168 | InputStream inputStream = originJar.getInputStream(inEntry)
169 | //将当前entry添加到临时文件中
170 | jarOutputStream.putNextEntry(outEntry)
171 | //插桩class
172 | if (checkClassInJar(name, config)) {
173 | ClassReader classReader = new ClassReader(IOUtils.toByteArray(inputStream))
174 | ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS)
175 | ClassVisitor cv = new InjectClassVisitor(classWriter, config)
176 | //原始的CR接收CW的访问,开始重排字节码
177 | classReader.accept(cv, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG)
178 | //回写
179 | byte[] code = classWriter.toByteArray()
180 | jarOutputStream.write(code)
181 | } else {
182 | // 直接拷贝,不插桩
183 | jarOutputStream.write(IOUtils.toByteArray(inputStream))
184 | }
185 | jarOutputStream.closeEntry()
186 | }
187 | //结束
188 | jarOutputStream.close()
189 | originJar.close()
190 | //重命名输出文件,因为可能同名,会覆盖
191 | def jarName = jarInput.name
192 | if (jarName.endsWith(".jar")) {
193 | jarName = jarName.substring(0, jarName.length() - 4)
194 | }
195 | //替换输出
196 | def dest = outputProvider.getContentLocation(jarName, jarInput.contentTypes, jarInput.scopes,
197 | Format.JAR)
198 | FileUtils.copyFile(jar, dest)
199 | jar.delete()
200 | }
201 | }
202 |
203 | private static boolean checkClassInJar(String name, PluginConfig config) {
204 | //eg: file in jar like: com/github/applib/Lib.class
205 | String dotClassName = name.replace("/", ".")
206 | boolean shoot = false;
207 | if (isClassFile(dotClassName)) {
208 | config.include.each { String configEle ->
209 | if (dotClassName.startsWith(configEle)) {
210 | if (config.logOpen) {
211 | println("file in jar like: " + name)
212 | }
213 | shoot = true
214 | return
215 | }
216 | }
217 | }
218 | return shoot
219 | }
220 |
221 | private static boolean checkClassInDir(String name, String path, PluginConfig config) {
222 | //eg: file in dir/module like: /Users/lotty/android/github/box/app/build/intermediates/classes/debug/com/github/boxapp/StringPool.class::StringPool.class
223 | String dotClassName = name.replace("/", ".")
224 | String absPath = path.replace("/", ".")
225 | boolean shoot = false
226 | if (isClassFile(dotClassName)) {
227 | config.include.each { String configEle ->
228 | if (absPath.contains(configEle)) {
229 | if (config.logOpen) {
230 | println("file in dir/module shoot: " + path)
231 | }
232 | shoot = true
233 | return
234 | }
235 | }
236 | }
237 | return shoot
238 | }
239 |
240 | private static boolean isClassFile(String cls) {
241 | return cls != null && cls.endsWith(".class")
242 | }
243 |
244 | }
245 |
--------------------------------------------------------------------------------
/string-plugin/src/main/java/com/github/box/InjectClassVisitor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Baidu, Inc. All Rights Reserved.
3 | */
4 | package com.github.box;
5 |
6 | import org.objectweb.asm.ClassVisitor;
7 | import org.objectweb.asm.FieldVisitor;
8 | import org.objectweb.asm.MethodVisitor;
9 | import org.objectweb.asm.Opcodes;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | /**
15 | * 全局的ClassVisitor,通过对方法名的判断,加载对应的MethodVisitor
16 | *
17 | * @author lotty
18 | */
19 | public class InjectClassVisitor extends ClassVisitor {
20 |
21 | private final static String CLINIT = "";
22 |
23 | /**
24 | * String 格式描述
25 | */
26 | private final static String STRING_DESC = "Ljava/lang/String;";
27 | /**
28 | * static + final 的16进制严格校验
29 | */
30 | private final static int ACCESS = 0x18;
31 |
32 | /**
33 | * 当前类名
34 | */
35 | private String owner;
36 |
37 | private PluginConfig config;
38 |
39 | private boolean hasClinit;
40 |
41 | /**
42 | * static final member para Key-> name Value->defaultValue
43 | */
44 | private Map fieldPairs = new HashMap<>();
45 |
46 | public InjectClassVisitor(ClassVisitor cv) {
47 | super(Opcodes.ASM5, cv);
48 | }
49 |
50 | public InjectClassVisitor(ClassVisitor cv, PluginConfig config) {
51 | super(Opcodes.ASM5, cv);
52 | this.config = config;
53 | }
54 |
55 | @Override
56 | public void visit(int version, int access, String name, String signature, String superName,
57 | String[] interfaces) {
58 | super.visit(version, access, name, signature, superName, interfaces);
59 | owner = name;
60 | }
61 |
62 | @Override
63 | public FieldVisitor visitField(int access, String name, String desc, String signature,
64 | Object defaultValue) {
65 | // 被 final + static 修饰,在类加载时被初始化赋值, instanceof covered null
66 | if (STRING_DESC.equals(desc) && (ACCESS & access) == ACCESS && defaultValue instanceof String) {
67 | String value = (String) defaultValue;
68 | if (!"".equals(value)) {
69 | fieldPairs.put(name, value);
70 | // 置空,在类初始化时重新赋值
71 | return super.visitField(access, name, desc, signature, null);
72 | }
73 | }
74 | return super.visitField(access, name, desc, signature, defaultValue);
75 | }
76 |
77 | @Override
78 | public MethodVisitor visitMethod(int access, String name, String desc, String signature,
79 | String[] exceptions) {
80 | MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
81 | if (CLINIT.equals(name)) {
82 | hasClinit = true;
83 | }
84 | return new InjectMethodVisitor(Opcodes.ASM5, mv, owner, name, config, fieldPairs);
85 | }
86 |
87 | @Override
88 | public void visitEnd() {
89 | if (!hasClinit && fieldPairs.size() > 0) {
90 | MethodVisitor mv = visitMethod(Opcodes.ACC_STATIC, CLINIT, "()V", null, null);
91 | mv.visitCode();
92 | mv.visitInsn(Opcodes.RETURN);
93 | // why 3 ?
94 | mv.visitMaxs(3, 0);
95 | mv.visitEnd();
96 | }
97 | super.visitEnd();
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/string-plugin/src/main/java/com/github/box/InjectMethodVisitor.java:
--------------------------------------------------------------------------------
1 | package com.github.box;
2 |
3 | import com.android.ddmlib.Log;
4 | import com.github.box.factory.StringCipherFactory;
5 | import com.github.box.util.CipherUtil;
6 |
7 | import org.objectweb.asm.MethodVisitor;
8 | import org.objectweb.asm.Opcodes;
9 |
10 | import java.util.HashMap;
11 | import java.util.Iterator;
12 | import java.util.Map;
13 | import java.util.Set;
14 |
15 | /**
16 | * MethodVisitor的基类
17 | *
18 | * @author lotty
19 | */
20 | public class InjectMethodVisitor extends MethodVisitor {
21 |
22 | private final static String STATIC_BLOCK_METHOD = "";
23 |
24 | private final static String TYPE_BASE64 = "base64";
25 | private final static String TYPE_HEX = "hex";
26 | private final static String TYPE_XOR = "xor";
27 | private final static String TYPE_AES = "aes";
28 |
29 | private final static int ZERO_KEY_SIZE = 0;
30 | private final static int XOR_KEY_SIZE = 8;
31 | private final static int AES_KEY_SIZE = 16;
32 |
33 | private final static String STRING_DE_METHOD_BASE64 = "xr";
34 | private final static String STRING_DE_METHOD_HEX = "rx";
35 | private final static String STRING_DE_METHOD_AES = "vv";
36 | private final static String STRING_DE_METHOD_XOR = "vx";
37 |
38 | private final static Map METHOD_MAP = new HashMap<>(4);
39 | private final static Map KEY_SIZE_MAP = new HashMap<>(4);
40 | private final static String STRING_ENC_P_3 =
41 | "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
42 |
43 | private final static String STRING_ENC_P_2 =
44 | "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
45 |
46 | private final static String STRING_ENC_P_1 =
47 | "(Ljava/lang/String;)Ljava/lang/String;";
48 |
49 | private static String STRING_ENC_OWNER = "com/github/box/XxVv";
50 |
51 | static {
52 | METHOD_MAP.put(TYPE_BASE64, STRING_DE_METHOD_BASE64);
53 | METHOD_MAP.put(TYPE_XOR, STRING_DE_METHOD_XOR);
54 | METHOD_MAP.put(TYPE_HEX, STRING_DE_METHOD_HEX);
55 | METHOD_MAP.put(TYPE_AES, STRING_DE_METHOD_AES);
56 |
57 | KEY_SIZE_MAP.put(TYPE_BASE64, ZERO_KEY_SIZE);
58 | KEY_SIZE_MAP.put(TYPE_XOR, XOR_KEY_SIZE);
59 | KEY_SIZE_MAP.put(TYPE_HEX, ZERO_KEY_SIZE);
60 | KEY_SIZE_MAP.put(TYPE_AES, AES_KEY_SIZE);
61 | }
62 |
63 | private String cls;
64 | private String method;
65 | private Map pairs;
66 | private PluginConfig config;
67 |
68 | public InjectMethodVisitor(int api, MethodVisitor mv, String cls, String method,
69 | PluginConfig config, Map pairs) {
70 | super(api, mv);
71 | this.cls = cls;
72 | this.pairs = pairs;
73 | this.method = method;
74 | this.config = config;
75 | }
76 |
77 | @Override
78 | public void visitCode() {
79 | // 在静态代码块中初始化变量
80 | mv.visitCode();
81 | if (STATIC_BLOCK_METHOD.equals(method)) {
82 | Set strings = pairs.keySet();
83 | Iterator iterator = strings.iterator();
84 | while (iterator.hasNext()) {
85 | String k = generateKey();
86 | String iv = generateIv();
87 | String field = iterator.next();
88 | String value = pairs.get(field);
89 | String encryption = cipher(config.encType).ee(value, k, iv);
90 | if (config.logOpen) {
91 | Log.e("plugin", cls + " || " + value + "--->" + encryption);
92 | }
93 | inject(encryption, k, iv);
94 | mv.visitFieldInsn(Opcodes.PUTSTATIC, cls, field, "Ljava/lang/String;");
95 | }
96 | }
97 | }
98 |
99 | @Override
100 | public void visitLdcInsn(Object cst) {
101 | if (cst instanceof String) {
102 | String k = generateKey();
103 | String iv = generateIv();
104 | String encryption = cipher(config.encType).ee((String) cst, k, iv);
105 | if (config.logOpen) {
106 | Log.e("plugin", cls + " || " + cst + "--->" + encryption);
107 | }
108 | inject(encryption, k, iv);
109 | } else {
110 | mv.visitLdcInsn(cst);
111 | }
112 | }
113 |
114 | private String generateKey() {
115 | if (TYPE_XOR.equals(config.encType) || TYPE_AES.equals(config.encType)) {
116 | int length = confirmLength();
117 | return CipherUtil.randomString(length);
118 | }
119 | return "";
120 | }
121 |
122 | private String generateIv() {
123 | if (TYPE_AES.equals(config.encType)) {
124 | int length = confirmLength();
125 | return CipherUtil.randomString(length);
126 | }
127 | return "";
128 | }
129 |
130 | private int confirmLength() {
131 | if (KEY_SIZE_MAP.containsKey(config.encType)) {
132 | return KEY_SIZE_MAP.get(config.encType);
133 | } else {
134 | return ZERO_KEY_SIZE;
135 | }
136 | }
137 |
138 | private StringCipher cipher(String cipherType) {
139 | return StringCipherFactory.create(cipherType);
140 | }
141 |
142 | private void inject(String encryption, String k, String iv) {
143 | if (TYPE_XOR.equals(config.encType)) {
144 | injectWithOnlyKey(encryption, k);
145 | } else if (TYPE_AES.equals(config.encType)) {
146 | injectWithIv(encryption, k, iv);
147 | } else {
148 | injectWithSelf(encryption);
149 | }
150 | }
151 |
152 | private void injectWithIv(String encryption, String k, String iv) {
153 | mv.visitLdcInsn(encryption);
154 | mv.visitLdcInsn(k);
155 | mv.visitLdcInsn(iv);
156 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, getDecryptClass(), getDecryptMethod(),
157 | STRING_ENC_P_3, false);
158 | }
159 |
160 | private void injectWithOnlyKey(String encryption, String k) {
161 | mv.visitLdcInsn(encryption);
162 | mv.visitLdcInsn(k);
163 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, getDecryptClass(), getDecryptMethod(),
164 | STRING_ENC_P_2, false);
165 | }
166 |
167 | private void injectWithSelf(String encryption) {
168 | mv.visitLdcInsn(encryption);
169 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, getDecryptClass(), getDecryptMethod(),
170 | STRING_ENC_P_1, false);
171 | }
172 |
173 | private String getDecryptMethod() {
174 | if (!TextUtil.isEmpty(config.pkg) && !TextUtil.isEmpty(config.method)) {
175 | return config.method;
176 | } else if (METHOD_MAP.containsKey(config.encType)) {
177 | return METHOD_MAP.get(config.encType);
178 | } else {
179 | return STRING_DE_METHOD_BASE64;
180 | }
181 | }
182 |
183 | private String getDecryptClass() {
184 | if (TextUtil.isEmpty(config.pkg) || TextUtil.isEmpty(config.method)) {
185 | return STRING_ENC_OWNER;
186 | } else {
187 | return config.pkg.replace(".","/");
188 | }
189 | }
190 |
191 | }
--------------------------------------------------------------------------------
/string-plugin/src/main/java/com/github/box/PluginConfig.java:
--------------------------------------------------------------------------------
1 | package com.github.box;
2 |
3 |
4 | public class PluginConfig {
5 |
6 | /**
7 | * 包含的路径
8 | */
9 | public String[] include;
10 |
11 | /**
12 | * 选择的加解密类型
13 | */
14 | public String encType;
15 |
16 | /**
17 | * 自定义解密的包名
18 | */
19 | public String pkg;
20 |
21 | /**
22 | * 自定义解密的方法名
23 | */
24 | public String method;
25 |
26 | /**
27 | * 是否打印日志
28 | */
29 | public boolean logOpen;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/string-plugin/src/main/java/com/github/box/TextUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.box;
2 |
3 | public class TextUtil {
4 |
5 | private final static String EMPTY = "";
6 |
7 | public static boolean isEmpty(String target) {
8 | return null == target || EMPTY.equals(target.trim());
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/string-plugin/src/main/resources/META-INF/gradle-plugins/encryption.properties:
--------------------------------------------------------------------------------
1 | implementation-class=com.github.box.EncryptionPlugin
--------------------------------------------------------------------------------