Android Studio GradleSync一直失败,提示:ERROR: Received close_notify during handshake
看https://stackoverflow.com/questions/59408006/error-received-close-notify-during-handshake
说是ssl连接的问题,关闭防火墙再试一次,果然就好了。本地java版本1.8
(
Gradle是什么,可以参见Unity2018导出Android工程并自行生成apk 这篇文章
GradleSync的时候是在干什么,可以参见https://www.jianshu.com/p/24a38f8400cc
)
!!!!!!!!!!!!下面都是记录其他Android相关的内容了,跟标题无关
目录
第二步 再使用android manager查看sdk版本.
1.Gradle sync failed: Failed to find target with hash string 'android-27'
2.Android Studio is using this JDK location: which is different to what Gradle uses by default:
3.一直在sync project with gradle files
android SDK vs JDK vs android NDK
方法一:命令行工具apktool、dex2jar、jd-gui
dex2jar工具:将classes.dex转换成jar文件
MAC想查看本机的android sdk的详细信息
第一步 先找到android sdk的存放路径
方式一:通过unity 找到现在的androidsdk的存放路径如图所示:
方式二:通过androidstudio ,如图所示:
第二步 再使用android manager查看sdk版本.
方式一:通过命令行打开
通过第1步找到的sdk的路径,cd到那个路径下的tools目录下
然后输入 ./android sdk
会弹出android manager的界面-android manager界面介绍:https://www.cnblogs.com/kangjianwei101/p/5621238.html
方式二:通过android studio 打开 略
Gradle Sync提示或者错误
1.Gradle sync failed: Failed to find target with hash string 'android-27'
这是从网上下载下来的项目。
找到他的配置中使用的编译sdk是27。但是我本地的sdk是29,所以修改为29即可,如下:
compileSdkVersion: 29,
buildToolsVersion: "29.0.2",
minSdkVersion : 21,
targetSdkVersion : 29,
按我的理解,compileSdkVersion 和 targetSdkVersion 最好是一样的。
2.Android Studio is using this JDK location: which is different to what Gradle uses by default:
Android Studio is using this JDK location:
I:\AndroidStudio\jre
which is different to what Gradle uses by default:
C:\Program Files\AdoptOpenJDK\jdk8u192-b12
Using different locations may spawn multiple Gradle daemons if
Gradle tasks are run from command line while using Android Studio.
(多个Gradle daemon,daemon)
修改jdk路径-file-project structure:
(所以androidstudio带了jdk)
3.一直在sync project with gradle files
找不到停止sync的按钮,就直接关掉as重新打开过
调试Android
1.使用adb logcat 打印在手机上的运行的日志
手机连上电脑,手机调成开发模式,使用adb命令查看看到连接上的设备:
adb devices
(把adb的路径存入PATH环境变量,就不用cd到adb所在的目录了,直接adb就可以了)
然后使用logcat命令,打印日志:(在手机上运行app,就能把产生的日志记录到out.txt中了)
指定 Unity 过滤器:
adb Logcat -s Unity > out.txt
或者不指定 Unity 过滤器:
adb Logcat > out.txt
辅助其他一些命令看输出(我一般是windows 安装了gitbash 在gitbash中输入命令):
也可以使用tail -f out.txt命令把日志打印到控制台
打印出来其他的也可以使用grep xxx进程号 专门打印这个游戏的进程的东西,因为手机里面的日志能多,运行的app很多。
Android中的打印日志的api有如下:
Log.i(TAG, "onBind方法被调用!");
ADB工具
ADB(Android Debug Bridge)是Android SDK中的一个工具,如果你安装了androidsdk,就可以在platform-tools这个路径下找到这个工具:
设置adb的路径存入PATH环境变量,方便敲命令。
adb devices ——查看当前连接设备:
adb logcat > 33333.log ——查看日志信息:
“-s”选项 : 设置默认的过滤器, 如
我们想要输出 “System.out” 标签的信息, 就可以使用:
adb logcat -s System.out
我们想要输出 “Unity” 标签的信息, 就可以使用:
adb logcat -s Unity
进入linux命令行即手机终端命令,#代表已经root了,$代表没有root权限——查看设备否有root权限
adb shell
adb install xxxx.apk ——在电脑端安装apk,无需拷贝到手机上安装了。参数-r,重新安装,-s 安装到sd卡。
adb uninstall 包名(比如com.xxx.xxx)——卸载app,-k只删除程序,不删除所用数据与缓存目录
adb pull/push xxxx ——取出/发送手机中的文件
adb:reset adb / adb kill-server / adb start-server —— 重启/杀死/启动adb
其他用到过以后再继续补充 https://blog.csdn.net/ezconn/article/details/85708000
2.monitor上查看android手机上的日志
C:\Android\android-sdk\tools\monitor.bat
双击一下运行就行了 下次试试
3.ddms.bat
在sdk的目录下 tools目录下有一个ddms.bat的文件,可以双击打开这个文件,就能看到打印信息,但是这个能看到所有的打印信息,需要过滤一下,具体方法还没用过下次用下 下次试试
(我本地的下载的sdk好像没有这个bat)
DDMS:(dalvik debug monitor service)安卓调试工具
4.Android Studio的打印面板
其实这个和第2种方法一样,只不过在使用的时候更方便
一些工具和概念
APKHelper工具
可以快速查看某个apk的版本号,build号等信息
相关术语
AVD: (android virtual machine):安卓虚拟设备,就是安卓的模拟器
ADT: (android development tools)安卓开发工具
DDMS:(dalvik debug monitor service)安卓调试工具
DX工具:将.class转换成.dex文件
查看手机cpu架构
adb device 查看连接的设备,
adb -s 192.168.56.101:5555 shell (如果只有一个设备就 直接adb shell) 进入手机的shell设置模式,
cat /proc/cpuinfo 查看手机CPU信息
Android系统目前支持以下七种不同的CPU架构:
- ARMv5,
- ARMv7 (从2010年起),
- x86 (从2011年起),
- MIPS (从2012年起),
- ARMv8,MIPS64和x86_64 (从2014年起),
以上 包含了3种CPU架构:
- MIPS——厂商MIPS——指令集mips,mips64
- ARM——厂商ARM——指令集armeabi(ARM v5),armeabi-v7a(ARM v7),arm64-v8a(ARM v8-ARM公司的首款支持64位指令集的处理器架构)
- X86——厂商Intel——指令集x86,x86_64
ARMv8指令集:
ARMv8架构,就是在MIPS64架构上增加了ARMv7架构中已经拥有的的TrustZone技术、虚拟化技术及NEON advanced SIMD技术等特性,研发成的。ARM是通过收购MIPS的形式得到了64位。
比如海思麒麟 960 处理器 是 cortex-A53 + cortex-A73,均是ARMv8-A构架的。
Cortex-A35、Cortex-A53、Cortex-A57、Cortex-A72——基于ARMv8-A架构
Cortex-A7、Cortex-A9、Cortex-A32、Cortex-A17——基于ARMv7-A 架构
64位处理器手机 vs 64位手机:
64位处理器手机:只要是处理器包含64架构位的,这种手机也许还运行不了64位程序,只是用来抢占市场,和32位手机比起来优势并不明显。
64位手机:它包含着64位处理器、64位标准系统、64位安卓虚拟机、以及64位程序。64位手机如果有app下有64位abi目录,就以64位运行,如果没有就以32位运行。
android SDK vs JDK vs android NDK
Android SDK
(Android Software Development Kit):
android 软件开发工具包,用来开发android的。
相当于安卓机器的操作系统,类似与windows操作系统,没有android sdk开发包的支持,就无法进行android应用开发,提供给你一个开发android应用的环境。
与java的关系:为了能够使 Java 开发者快速转入 android应用的开发,所以仿照 Java API 重新进行了实现,因而大多数标准库中的资源都可以按照原来java开发的方式使用。
如何查看android sdk版本号:上面使用mac查看android sdk的版本号
JDK
java软件开发工具包。
这个包中提供了java语言的类库,也就是你要用java语言,那么电脑上必须装jdk。
unity中关于android的设置关于jdk和sdk的存放路径:
因为unity导出打包成android应用,就需要用到android sdk,安卓应用用java开发,java开发就需要底层的java类库,这些类库就被封装在JDK中。
查看版本号:
java -version
Android NDK
摘自 https://blog.csdn.net/huang_yx005/article/details/78780450
(Native Development Kit):NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。Android程序运行在Dalvik虚拟机中。Android的SDK基于Java实现,所以基于Android SDK进行开发的第三方应用一般都使用Java语言,但这并不等同于“第三方应用只能使用Java”,也就是说我们还可以采用C/C++语言。
NDK是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so(通过NDK编译C/C++生成的)和java应用一起打包成apk(AndroidPackage的缩写,Android安装包)。这些工具对开发者的帮助是巨大的。
NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。它可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
NDK提供了一份稳定、功能有限的API头文件声明,Google明确声明该API是稳定的,在后续所有版本中都稳定支持当前发布的API。从该版本的NDK中看出,这些API支持的功能非常有限,包含有:C标准库(libc)、标准数学库(libm)、压缩库(libz)、Log库(liblog)。
Android Studio的使用
下载android studio https://developer.android.com/studio
安装好了以后马上启动
提示没有安装android sdk(android sdk 的具体介绍 在本篇文章 和 Unity2018导出Android工程并自行生成apk 搜就行了):
点击cancle,进入初次登陆配置界面,最后选择 默认推荐配置就行了,会给你下载android sdk。
新建项目以及构建以及测试
IDE下载安装好了,用一下。
选择新建一个项目,选择empty activity,填到最后第一次会开始下载gradle,gradle sync之类的。
选择empty activity会生成一个 MainActivity.java 和 activity_main.xml
MainActivity.java:
package xdw.com;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivityextends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 调用父类的方法
setContentView(R.layout.activity_main); // 加载布局资源文件 layout目录下 activity_main.xml
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
等一段时间,等gradle sync成功了以后,进行build apk (其实就是调用gradle 进行 build 的工作了):
build成功以后,就可以点击 Run--》Run “app”进行测试了(如果没有配置模拟机,点击Tools--》AVD Manager(andriod virtual device)进行配置) :
自己遍历一下多点点探索一下。
Project的项目结构模式
.gradle和.idea目录 ——是AS自动生成的文件,不用编辑。
app目录 ——包含了代码和资源文件,开发是在这个目录下进行的。
gradle目录 ——包含了gradle wrapper的配置文件。
.gitignore文件 ——是用来将指定的目录或文件排除在版本控制外。
build.gradle文件 ——是项目全局的gradle构建脚本。
gradle.properties文件 ——是全局的gradle配置文件。
gradlew和gradlew.bat文件——是用来在在命令行界面执行gradle命令的,前者用于Linux或Mac系统,后者用于Windows系统。
HelloWorld.iml文件 ——是IDEA项目自动生成的文件,不需要更改。
local.properties文件 ——用于指定本机Android SDK路径,通常不用更改,除非本机的Android SDK位置发生变化。
settings.gradle文件 ——用于指定项目中所有引入的模块。
加粗的都是跟gradle构建工具有关的配置。
某模块下目录内容-app
build——构建目录,包含编译时自动生成的文件。
libs——依赖的包,用来存放第三方jar包。
src——开发大部分的东西都放在这个文件夹中
androidTest——用来编写Android Test测试用例,可以对项目进行一些自动化测试。
main
————————————————————————————————————————
java——放Java文件
assets目录,虽然这里没有,但是我们可以自己创建,也是存放资源文件的。
raw目录:虽然这里没有,但是我们可以自己创建, 用于存放各种原生资源(音频,视频,一些XML文件等),我们可以通过openRawResource(int id)来获得资源的二进制流!其实和Assets差不多,不过这里面的资源会在R文件那里生成一个资源id而已。
anim目录:动画有两种:属性动画和补间动画:animator:存放属性动画的XML文件;anim:存放补间动画的XML文件。
res存放资源文件,包括图片、布局、字符串等。图片放在drawable目录下,布局放在layout目录下,字符串放在values目录下。drawable 和 mipmap 都是图片资源 ,使用mipmap会在图片缩放在提供一定的性能优化。不同系统会根据屏幕分辨率来选择-hdpi,-mdpi,-xmdpi,-xxhdpi下的对应图片,存放只是大小和像素不一样的图片!原则是使用最接近的密度级别!另外如果你想禁止Android不跟随屏幕密度加载不同文件夹的资源,只需在AndroidManifest.xml文件中添加android:anyDensity="false"字段即可。(res下的资源通过资源id访问到对应的资源;assets下的资源通过AssetManager以二进制流的形式来读取。)
————————————————————————————————————————
drawable 图像资源,存放各种位图文件,(.png,.jpg,.9png,.gif等)除此之外可能是一些其他的drawable类型的XML文件
mipmap 也是图片资源 ,使用mipmap会在图片缩放在提供一定的性能优化。
mipmap-hdpi:高分辨率,一般我们把图片丢这里
mipmap-mdpi:**中等分辨率,很少,除非兼容的的手机很旧
mipmap-xhdpi:超高分辨率,手机屏幕材质越来越好,以后估计会慢慢往这里过渡
mipmap-xxhdpi:超超高分辨率,这个在高端机上有所体现
layout 布局资源:该目录下存放的就是我们的布局文件,另外在一些特定的机型上,我们做屏幕适配,比如480*320这样的手机,我们会另外创建一套布局,就行:layout-480x320这样的文件夹。
menu 菜单资源:在以前有物理菜单按钮,即menu键的手机上,用的较多,现在用的并不多,菜单项相关的资源xml可在这里编写,不知道谷歌会不会出新的东西来替代菜单了~
value :demens.xml:定义尺寸资源;string.xml:定义字符串资源;styles.xml:定义样式资源;colors.xml:定义颜色资源;arrays.xml:定义数组资源;attrs.xml:自定义控件时用的较多,自定义控件的属性;theme主题文件,和styles很相似,但是会对整个应用中的Actvitiy或指定Activity起作用,一般是改变窗口外观的!可在Java代码中通过setTheme使用,或者在Androidmanifest.xml中为<application...>添加theme的属性!
demens:css配置资源
string:字符串资源
styles:style资源
PS:你可能看到过这样的values目录:values-w820dp,values-v11等,前者w代表平板设备,820dp代表屏幕宽度;而v11这样代表在API(11),即android 3.0后才会用到的
————————————————————————————————————————
AndroidManifest.xml——配置文件,定义的四大组件都要在这里注册,权限的声明也在这里。
————————————————————————————————————————
test——用来编写Unit Test测试用例。
.gitignore——将app模块中的指定目录或文件排除在版本控制外。
build.gradle——app模块的Gradle构建脚本,指定构建相关的配置。
proguard-rules.pro——用于指定项目代码的混淆规则。
相关的Gradle构建命令
1)Build下的MakeProject
点MakeProject其实是执行的BuildVariants中配置的类型,如下图就是assembleDebug
2)Android Studio中内置的gradle命令
在AndroidStudio的最右侧,双击就执行了,同样可以在控制台的Build界面看到
assemble就是assembleDebug和assembleRelease 这两个Task
3) Gradle 中Task的使用
官方文档 https://docs.gradle.org/current/dsl/org.gradle.api.Task.html
一个Task代表一个构建工作的原子操作,例如编译 或者生成javadoc。
Gradle中,每一个待编译的工程都叫一个Project,每一个Project在构建的时候都包含一系列的Task。
(Gradle把构建的步骤分成了一个一个的task,我们可以定义task Unity2018导出Android工程并自行生成apk 这篇文章,之前说的gradle文件中定义task)
比如一个Android APK的编译可能包含:
Java源码编译Task、
资源编译Task、
JNI编译Task、
lint检查Task、
打包生成APK的Task、
签名Task等。
下面就是一个自定义的简单的task 的一个例子:
task hello {
println 'Hello world!'
}
// 语法
task myTask
task myTask { configure closure } // 花括号就是一个closure
// <<符号是doLast的缩写 。
// 我们创建了一个Task对象,同时把closure做为一个action加到这个Task的action队列中,并且告诉它“最后才执行这个closure”。
// 一个Task包含若干Action。所以,Task有doFirst和doLast两个函数,用于添加需要最先执行的Action和需要和需要最后执行的Action。task myType << { task action }
// type: SomeType 指定Type,告诉Gradle这个新建的Task对象会从哪个基类Task派生。Gradle本身提供有Copy、Delete、Sync(直接到官网搜方法)等
task myTask(type: SomeType)
task myTask(type: SomeType) { configure closure }
插件本身就是包含了若干Task的(见下文的 gradlew tasks)。
在AndroidStudio中的console台输入gradlew help ,执行help(即task task) :显示gradle版本号以及提示命令
G:\Project_Android>gradlew help
> Configure project :app
Hello world!
> Task :help
Welcome to Gradle 5.4.1.
To run a build, run gradlew <task> ...
To see a list of available tasks, run gradlew tasks
To see a list of command-line options, run gradlew --help
To see more detail about a task, run gradlew help --task <task>
For troubleshooting, visit https://help.gradle.org
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed
在AndroidStudio中的console台输入gradlew tasks,执行tasks Task,可以查看有哪些可用的任务。太长不截图了。
每当我们在Android Studio点击 build,rebuild,clean菜单的时候,执行的就是一些gradle task.
基本的 task:
- assemble:对所有的 buildType 生成 apk 包。
(在Build tasks中,assemble - Assemble main outputs for all the variants.) - clean:移除所有的编译输出文件,比如apk
(在Build tasks中,clean - Deletes the build directory.) - check:执行lint检测编译。
(在Verification tasks中,check - Runs all checks.) - build:同时执行assemble和check命令
(在Build tasks中,Assembles and tests this project.) - install:将编译后的apk 安装到连接的设备
- uninstall:卸载apk
其中assemble用的比较多
默认的 assmeble 会依赖 assembleDebug 和assembleRelease,如果直接执行assmeble,最后会编译debug,和release 的所有版本出来。如果我们只需要编译debug 版本,我们可以运行assembleDebug。
如果执行gradlew assembleDebug4zj,就是编译buildType中定义的Debug4zj模式,即它可以结合构建类型(buildTypes)去创建task。
如果执行gradlew assembleBaiduDebug4zj 就会打出,buildType中定义的Debug4zj模式+productFlavors 中的定义的Baidu模式,即可以结合Build Variants((projectFlavors+buildTypes))来创建新的Task。
查看某个具体task的含义,比如sourceSets
G:\Project_Android>gradlew help --task sourceSets
> Configure project :app
Hello world!
> Task :help
Detailed task information for sourceSets
Path
:app:sourceSets
Type
SourceSetsTask (com.android.build.gradle.internal.tasks.SourceSetsTask)
Description
Prints out all the source sets defined in this project.
Group
Android
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
使用Android Studio建立JNI工程
是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分。JNI是java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以调用java代码。JNI 是本地编程接口,Java和C/C++互相通过的接口。Java通过C/C++使用本地的代码的一个关键性原因在于C/C++代码的高效性。
由于Java是虚拟机语言(指需要被编译成虚拟机代码,由虚拟机执行的语言)容易被人反编译,一般核心代码以C/C++编写(将源代码编译为机器码,直接由CPU执行代码),然后把C/C++编写的核心代码编译为一个动态链接库,即文件后缀为".so"的ELF文件,以SO文件的形式供上层JAVA代码调用,以保证安全性。
JNI——Java Native Interface,Native即C/C++,即Java层和Native层的相互调用。
java平台提供了JNI标准(Java Native Interface),建立JNI工程使得Java调用C/C++的函数。
Google为Android的原生开发提供了开发者工具NDK(Native Development Kit),用来编译C/C++项目。ndk编译C/C++源码生成.so文件,ndk还可以讲so文件和java文件一起打包成apk。
java层如何调用native层函数的:
简单一点的:https://www.jianshu.com/p/186954700766
更加详细的:https://bbs.pediy.com/thread-224672.htm
AAR相关
在AndroidStudio中,选择新增Module,有新增Android library和Java library,两者的区别Android library Module是生成aar文件,Java library Module生成jar包。
1.首先创建一个 Android library Module.
2.等待 Gradle 构建完毕, 就可以在项目名称/模块名称/build/outputs/aar/中找到这个库项目的 AAR 文件了。
3.如果修改了代码,也可以通过 Build > Make Project 的方式重新生成文件。
AAR包文件结构
AAR 文件的文件扩展名为 .aar,一份 aar 文件其实就是一份 zip 包,和 jar 不同的是,它将一些资源文件、第三方库文件、so 文件(C++)等等都打包在内,而代码文件编译后压缩在classes.jar中。
解压以后aar必然包含以下内容:
/AndroidManifest.xml
/classes.jar
/res/
/R.txt
此外,根据打包的 Library Module 情况不同,打包出来的 AAR 文件也可能包含以下内容:
/assets/
/libs/名称.jar
/jni/abi 名称/名称.so(其中 abi 名称 是 Android 支持的 ABI 之一)
/proguard.txt
/lint.jar
项目中引用AAR包
当其他 Module引用了引用了aar的library module时,也需要在他的build.gradle中加入存放的路径声明。
即如果当前Module需要一个aar包内容(直接还是间接包含),不论aar包是不是在当前Module中,都需要在build.gradle中声明它所在的路径。如果项目中这样的Module比较多,可以在录项目的根build.gradle将所有包含aar包的模块名列出,这样不论是本Module或其他Module都不需要单独配置路径了:
allprojects {
repositories {
jcenter()
google()
flatDir {
dirs "../moudle-A/libs,../moudle-B/libs,../moudle-C/libs".split(",")
}
}
}
AAR包使用注意事项
-
使用 Android Studio 打包出来的 AAR ,不会将其依赖的三方库打包进去。
-
如果是应用模块(application)引用aar,那么其 minSdkVersion 必须大于或等于 Library Module(aar) 中定义的。AAR 作为相关应用模块的一部分编译,因此,库模块中使用的 API 必须与应用模块支持的平台版本兼容,所以 AAR 中的 minSdkVersion 要尽量的设置低一点。
-
资源合并问题。如果 aar 中有资源文件,集成过程中,很容易出现资源冲突,例如两个相同名字的图片什么的。可以 library Module 的 build.gradle 中设置资源前缀resourcePrefix,起的是约束作用,不会自动帮你修改资源的名称。如果我们没有加上前缀,就会报错!
android {
resourcePrefix "<前缀>"
}
4. aar 不能使用 assets 原始资源(虽然好像aar解压出来是有assets目录, 但是里面是空的,不知道有没有不是空的例子)
APK的签名
保证了apk包里的文件不能被随意替换。
拿到一个apk包后,如果想要替换里面的一幅图片,一段代码, 或一段版权信息,想直接解压缩、替换再重新打包,是不可能的。需要重新签名才可以。
签名和校验过程
校验Verification:
1.提取数据data部分,通过一个hash函数加密算法,计算出一个固定长度的hash值,假设其值为A(数字摘要)。
2.提取签名signature部分,通过一个公钥进行解密,得到假设其值为B。
3.比较这两个值A值是否和B值一致。如果一致就是通过校验了。
上面最主要的两个东西就是加密算法 和 公钥 ,这两个都存在证书Certificate中的。证书Certificate和签名signature部分都是在签名过程中加上的。数字证书Certificate是身份认证机构(Certificate Authority)颁发的,包含了以下信息:
1)证书颁发机构,证书颁发机构签名,证书绑定的服务器域名,证书版本、有效期——用来确保APK来源是可靠的值得信任的。
2)签名使用的加密算法(非对称算法,如RSA),公钥——下图的Hash<-->Signature之间的加密解密过程。
3) 等等
apk中的签名相关文件——META-INF文件夹
apk中个解压出来查看
① MANIFEST.MF:
它的内容是 APK 包中每个文件的名字及每个文件的 SHA1 哈希摘要。
可以通过文本软件打开 MANIFEST.MF,里面列出了apk中所有的文件,以及它们的sha1摘要,摘要字符串是通过base64编码的。
验证,先计算某文件的sha1值,然后base64转成字符串:
windows下cmd计算sha1:
certutil -hashfile filename sha1
计算出来的值转base64,通过在线网页转http://tomeko.net/online_tools/hex_to_base64.php
② CERT.SF:
这里不一定是CERT.SF,也可能BDMOBILE.SF、NETDISK_.SF等,总之是SF文件。
它保存的是刚刚生成的MANIFEST.MF文件的SHA1 哈希摘要,以及 MANIFEST.MF 文件中每一个条目的SHA1哈希摘要。每一个条目的意思是比如下面是MANIFEST.MF 文件中的一个条目:
Name: AndroidManifest.xml
SHA1-Digest: wOpZJOZ+h0foJSKvIu0yeh8s4pg=
把这个保存到新的文件中(后面要有两个换行符),然后再计算这个文件的sha1摘要,就得到了对应的一个CERT.SF的条目:
Name: AndroidManifest.xml
SHA1-Digest: tbGwGWbAeb3kPk8MYkyk1MQ6kUY=
③ CERT.RSA:这个文件保存了 APK 包的签名和证书的公钥信息。
是二进制文件。
这个文件保存了签名者的证书信息,以及对CERT.SF文件(第② 步)的签名。
整个apk签名是在apk中写入一个“指纹”。指纹写入以后,Apk中有任何修改,都会导致这个指纹无效,Android系统在安装Apk进行签名校验时就会不通过,从而保证了安全性。
APK的校验过程
上面说的是签名过程,接下来看apk安装过程是怎样进行签名校验的。校验过程和签名过程刚好相反:
1.首先校验cert.sf文件的签名
计算cert.sf文件的摘要,与通过签名者公钥解密签名得到的摘要(通过cert.rsa得到的签名以及公钥,计算出摘要)进行对比,如果一致则进入下一步;(防止篡改cert.sf)
2.校验manifest.mf文件的完整性
计算manifest.mf文件的摘要,与cert.sf主属性中记录的摘要进行对比,如一致则逐一校验mf文件各个条目的完整性;(防止篡改manifest.mf)
3.校验apk中每个文件的完整性
逐一计算apk中每个文件(META-INF目录除外)的摘要,与mf中的记录进行对比,如全部一致,刚校验通过;(防止篡改apk内容)
4.校验签名的一致性
如果是升级安装,还需校验证书签名是否与已安装app一致。(如果把apk内容和签名信息一同全部篡改这相当于对apk进行了重新签名,在此apk没有安装到系统中的情况下,是可以正常安装的,这相当于是一个新的app;但如果进行覆盖安装,则证书不一证,安装失败。)
apk的签名文件——keystore
我们在对Apk签名时并没有直接指定私钥、公钥和数字证书,而是使用keystore文件。这些信息都包含在了keystore文件中,也就是相当于一个签名文件了。
keystore文件是一个密钥库,也就是说它可以存储多对密钥和证书。keystore的密码是用于保护keystore本身的,一对密钥和证书是通过alias(key别名)来区分的。
ps:keystore文件可以使用AndroidStudio或者其他一些生成比如Androidkiller,或者keytool命令行。
设置了keystore以后,打包后的apk就会包含了签名相关信息——META-INF文件夹
1)Unity的默认证书keystore文件
unity没有设置过证书打出来的apk也是包含签名的。
查看在playersetting里选择了Use Existing Keystore,默认选的是unsigned(debug)的。
那证书文件在哪里呢?windows下是在:C:\Users<用户名>.Android\debug.keystore。mac机也是在\Users<用户名>.Android下不要默认是隐藏文件夹(用command+shift+.显示出来就能看到)
使用keytool工具在控制台输入查看该密钥的信息(这个key的密码是:android )
keytool -list -keystore debug.keystore
keytool -list -v -keystore xxx.keystore -storepass 密码
ps:keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。
(在JDK 1.4以后的版本中都包含了keytool 这一工具,它的位置为%JAVA_HOME%\bin\keytool.exe)
Java KeyStore 生成方式(后面会介绍keytool工具,jdk自带的keytool):
【生成】证书库
keytool -genkey -v -keystore strange.keystore -alias strange -keyalg RSA -keysize 2048 -validity 10000
【查看】证书库
keytool -list -v -keystore {path2jks,证书的路径} -storepass “pass"
keytool -genkeypair 生成证书命名
-alias dishui 别名
-keyalg "RSA" 加密方式
-keystore "name" 输出的证书名
-storepass 123456 密码
2)gradle中指定keystore文件
gradle会指定签名文件配置:
signingConfigs {
debug {
keyAlias 'e'
keyPassword ''
storeFile file('e.keystore')
storePassword ''
}
}
3)androidstudio中
签名过程的代码实现
具体过程可参考apksigner源码
public static void main(String[] args) {
......
//生成MANIFEST.MF文件,遍历apk的所有文件,计算除META-INF目录下的
//.SF/.RSA/.DSA文件外所有文件的摘要。
JarEntry je;
Manifest manifest = addDigestsToManifest(inputJar);
// MANIFEST.MF
je = new JarEntry(JarFile.MANIFEST_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
manifest.write(outputJar);
// 生成CERT.SF文件
je = new JarEntry(CERT_SF_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//计算MF文件摘要,及MF相应条目的摘要
writeSignatureFile(manifest, baos);
//计算SF文件的摘要
byte[] signedData = baos.toByteArray();
outputJar.write(signedData);
// 生成CERT.RSA
// 对SF文件的摘要(signedData)进行签名,将证书信息一同写入RSA文件中
je = new JarEntry(CERT_RSA_NAME);
je.setTime(timestamp);
outputJar.putNextEntry(je);
writeSignatureBlock(new CMSProcessableByteArray(signedData),
publicKey, privateKey, outputJar);
outputJar.close();
......
}
Android APK的反编译方法
在apk中的AndroidManifest.xml是经过压缩的,可以通过AXMLPrinter2工具解开,具体命令为:
java -jar AXMLPrinter2.jar AndroidManifest.xml
Android模拟器中提供了一个dex文件的反编译工具,dexdump。
用法为首先启动Android模拟器,把要查看的dex文件用adb push上传的模拟器中,然后通过adb shell登录,找到要查看的dex文件,执行dexdump xxx.dex。(没试过)
方法一:命令行工具apktool、dex2jar、jd-gui
https://blog.csdn.net/jw_66666/article/details/51930808 这篇文章最后有上述工具的下载地址
apktool工具:获得图片与XML资源
反编译工具在apktool目录下,解压得到3个文件:aapt.exe,apktool.bat,apktool.jar
将需要反编译的APK文件放到该目录下,打开命令行界面 ,定位到apktool文件夹,输入以下命令:
apktool.bat d XXXX.apk foldernameAAA
在foldername下面就是反编译完成的,其中的xml都是正常显示不是乱码的,跟直接改zip解压出来的不一样。
- 1):运行上述命令如果出现以下错误
Exception in thread “main” brut.androlib.AndrolibException: Could not decode arsc file
Apktool的bug使用其他版本的Apktool,我在使用apktool_2.3.3.jar中遇到了这个问题,使用如apktool_2.3.1.jar是好的,如果你也遇到了这个问题不妨换个Apktool版本试一下。apktool下载地址https://ibotpeaches.github.io/Apktool/
- 2):将反编译完的文件重新打包成apk,比如修改了某些东西
输入apktool.bat b test(你编译出来文件夹)便可。新的apk会生成在dist文件夹里。
apktool.bat b foldernameAAA
- 3):重新打包的apk需要重新签名
签名工具在auto-sign目录下,把apk放到下面(AAA.apk是输入apk,BBB.apk是签名以后的输出apk)
java -jar signapk.jar testkey.x509.pem testkey.pk8 AAA.apk BBB.apk
其中.pem和.pk8都是证书相关的。也可以用keytool工具自行制作一个证书进行签名。
dex2jar工具:将classes.dex转换成jar文件
反编译dex在dex2jar和jd-gui目录下
首先将要反编译的APK后缀名改为.rar或则 .zip,并解压,得到其中的classes.dex文件(它就是java文件编译再通过dx工具打包而成的),将获取到的classes.dex放到之前解压出来的工具dex2jar文件夹内,
再在命令行下定位到dex2jar.bat所在目录,输入
dex2jar.bat classes.dex:
可以看到在该目录下会生成一个classes_dex2jar.jar的文件。
jd-gui工具:查看jar包中的Java代码
打开工具jd-gui文件夹里的jd-gui.exe,用该工具打开之前生成的classes_dex2jar.jar文件,便可以看到源码了。
如果是被混淆(https://blog.csdn.net/fengyuzhengfan/article/details/39187989)过的代码,类文件名称以及里面的方法名称都会以a,b,c....之类的样式命名。
用这个工具查看unity提供的android插件classes.jar:
C:\unity5\Unity**Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes\classes.jar其中的UnityPlayer类和UnityPlayerActivity可以看看:
image.png
另外有一篇关于mac的:反编译Android APK详细操作指南[ApkTool,dex2jar,JD-GUI] for Mac
https://blog.csdn.net/fengyuzhengfan/article/details/80286704
使用AndroidKiller反编译源码,修改后重新打包签名记录:
https://blog.csdn.net/u013440413/article/details/103726317
AndroidKiller编译CreateProcess error=206 文件名扩展太长:
https://blog.csdn.net/undiif123/article/details/88096631
方法二,可视化的反编译工具androidkiller
https://blog.csdn.net/iamlegendary/article/details/79468400
使用androidkiller看反编译,其中的smali文件夹中内容,其实就是classes.dex反编译过来的smali文件
如果要看java源码,那么就跟方法一中通过dex2jar,然后gui去看jar的原始代码。
一个简单的例子,可以看到app的组件情况
方法三
Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)!
https://blog.csdn.net/Android_Tutor/article/details/5724435
其中smali和baksmali下载不到。
大概就是通过直接改后缀解压,然后AXMLPrinter2可以查看其中乱码的xml。
baksmali 用来将classes.dex反编译成 .smali
smali用来将 .smali 打包成 classes.dex
注
对反编译以后的包进行修改进行二次打包以后,需要进行签名才能使用。