1. 反编译
工具: Android 逆向助手
android应用扩展名 apk 实际可以理解为: .zip
把apk扩展名修改成zip之后解压 就可以获取到应用的图片资源 如果想看到应用的xml文件(布局 动画 清单文件 )
反编译 apktool->反编译 dextojar -> classes.dex->.jar
jdgui 直接查看.jar的java代码
2. 反汇编
so库反汇编工具: IDA Pro
3. 锅炉压力案例
3.1 布局文件
<?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">
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="开始检测"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="结束检测"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_start" />
<!--<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="50dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="50dp"
android:maxHeight="50dp"
android:minHeight="30dp"
app:layout_constraintTop_toBottomOf="@id/btn_stop" />-->
<com.example.demo.MyPressureView
android:id="@+id/pressure"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintTop_toBottomOf="@id/btn_stop" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.2 测试文件
public class MainActivity extends AppCompatActivity {
//private ProgressBar progressBar;
private MyPressureView pressureView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//progressBar = findViewById(R.id.progressBar);
//progressBar.setMax(100);
}
//测试方法
private void initView(){
pressureView = findViewById(R.id.pressure);
findViewById(R.id.btn_start).setOnClickListener(view -> new Thread(new Runnable() {
@Override
public void run() {
startMoniter();
}
}).start());
findViewById(R.id.btn_stop).setOnClickListener(view -> stopMoniter());
}
//设置进度条的值
public void setPressure(int progress) {
//progressBar.setProgress(progress);
pressureView.setPressure(progress);
}
static {
System.loadLibrary("pressure");
}
//开始检测压力的本地方法
public native void startMoniter();
//结束检测压力的本地方法
public native void stopMoniter();
}
3.3 native层,CMakeLists.txt文件
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.18.1)
# Declares and names the project.
project("pressure")
add_library( # Sets the name of the library.
pressure
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
main_jni.cpp
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
pressure
# Links the target library to the log library
# included in the NDK.
${log-lib} )
3.4 cpp文件及实现
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <cstdlib>
#include <unistd.h>
/* Header for class com_example_demo_MainActivity */
#ifndef _Included_com_example_demo_MainActivity
#define _Included_com_example_demo_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
//获取压力的方法: 模拟返回 1 至 100 的随机数
int getPressure() {
return rand() % 501;
}
int flag = 1;
/*
* Class: com_example_demo_MainActivity
* Method: startMoniter
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_demo_MainActivity_startMoniter
(JNIEnv *env, jobject thiz) {
//1. 获取字节码
jclass clazz = env->FindClass("com/example/demo/MainActivity");
//2.找到方法
jmethodID methodId = env->GetMethodID(clazz, "setPressure", "(I)V");
flag = 1;
while (flag) {
//sleep 1 在 linux 中就是睡1秒钟
sleep(1);
//3.调用方法
env->CallVoidMethod(thiz, methodId, getPressure());
}
env->CallVoidMethod(thiz, methodId, 0);
}
/*
* Class: com_example_demo_MainActivity
* Method: stopMoniter
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_demo_MainActivity_stopMoniter
(JNIEnv *env, jobject thiz) {
flag = 0;
}
#ifdef __cplusplus
}
#endif
#endif
3.5 动画自定义View
public class MyPressureView extends View {
private int pressure = 0;
private Paint paint = new Paint();
//在动态创建控件的时候使用
public MyPressureView(Context context) {
super(context);
}
//AttributeSet 属性集合 解析 xml 文件时,属性都会封装在这个 AttributeSet 中
public MyPressureView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
//defStyleAttr 在xml 文件中声明一个样式的时候,解析 xml 之后 就会转换成这个 defStyleAttr
public MyPressureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyPressureView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (pressure > 300) {
paint.setColor(Color.RED);
} else if (pressure > 150) {
paint.setColor(Color.MAGENTA);
} else {
paint.setColor(Color.GREEN);
}
paint.setTextSize(45);
//paint.setColor(Color.RED);
canvas.drawText("当前压力值: " + pressure, getWidth() / 2 - 150, 30, paint);
//画矩形 用来表示压力值
canvas.drawRect(getWidth() / 2 - 100, 570 - pressure, getWidth() / 2 + 100, 570, paint);
}
/**
* 设置压力大小
*
* @param pressure
*/
public void setPressure(int pressure) {
this.pressure = pressure;
//当 pressure 发生改变要重绘界面
//使当前的页面无效 如果view 是可见的在未来的某一时刻 会调用 onDraw 重新绘制页面
//invalidate();
//子线程刷新页面 要用 postInvalidate invalidate只能在主线程上使用
postInvalidate();
}
}