Android APP inversa - solicitud de red

Módulos comunes para solicitudes de red de Android

  • Las solicitudes Web HTTP comunes se dividen en solicitudes GET y POST. Python usa urllib y módulos de solicitudes, y Android usa okhttp y módulos de actualización . La relación entre okhttp y actualización es la misma que entre urllib y solicitudes. Ambos están reencapsulados sobre la base del primero para que sea más cómodo de usar.

  • El paquete de datos de la solicitud Web HTTP se puede dividir en dos formularios, el formulario de formulario y la cadena json En Python, estos dos formularios se distinguen por los parámetros del método de solicitudes, pero en Android, okhttp también tendrá envíos correspondientes. método de forma.

  • Cuando se recibe un paquete web, si se recibe la cadena json recibida, los datos deben deserializarse. El módulo de solicitudes en python nos ayuda a completar este trabajo, pero en Android, el módulo Gson debe introducirse para lograr el cambio de deserialización.

  • En las aplicaciones web del navegador, los archivos de cookies se usan para guardar información del usuario y los archivos xml se usan para lograr funciones similares en Android, por lo que también es necesario aprender a operar archivos xml en Android.

OKHTTP

Antes de usar okhttp, realice la siguiente configuración:

implementation “com.squareup.okhttp3:okhttp:4.9.1”
  • Configuración, en AndroidManifest.xml, la etiqueta de la aplicación agregada por encima del mismo nivel
    solo puede enviar solicitudes https.

  • Configuración, en AndroidManifest.xml, agregue android:networkSecurityConfig="@xml/network_security_config" dentro de la etiqueta de la aplicación

Cree una nueva carpeta xml en el directorio res, cree un nuevo archivo network_security_config.xml y escriba el siguiente contenido:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!--禁用掉明文流量请求的检查-->
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

Cree una solicitud GET ---> [crear hilo] --> de lo contrario informe de un error

String username = String.valueOf(txtUser.getText());
String password = String.valueOf(txtPwd.getText());

HashMap<String, String> dataMap = new HashMap<String, String>();
dataMap.put("username", username);
dataMap.put("password", password);


// 1. 将用户名和密码 发送到后台 (第三方 OKHttp)
//  1.1 引入依赖 bulid.gradle 文件中 引入 implementation "com.squareup.okhttp3:okhttp:4.9.1"
//  1.2 在Android中,默认不允许发送网络请求; 在AndroidManifest.xml 中 配置 <uses-permission android:name="android.permission.INTERNET"/>
//  1.3 调用 OKHttp包去发送请求。

// 1.3.1 创建 GET 请求 ---> [创建线程]--> 否则报错
// 创建线程并执行 run 方法
new Thread(){
    @Override
    public void run(){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/course/actual/?category_id=1").build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            Log.i("登录界面--->", resString);
            // 获取数据并处理


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

Crear solicitud POST ---> [crear hilo]

formularioFormato de formulario

  • Los paquetes se envían en un formato de formulario como:

username=xxxx&password=123
new Thread(){
    @Override
    public void run(){
        OkHttpClient client = new OkHttpClient();
        // 构建请求体
        FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();
        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            Log.i("登录界面--->", resString);
            // 获取数据并处理


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

formato json

  • El paquete de datos se envía en formato json, por ejemplo:

{
    username:"xxxx",
    password:123,
}
new Thread() {
    @Override
    public void run() {
        OkHttpClient client = new OkHttpClient();
        // 构建请求体
        // FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();

        //JSONObject json = new JSONObject();
        //json.put("username", "dk");
        //json.put("password", "123");
        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());

        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            // Json反序列化,字符串转换成对象.
            // json.load(json字符串) --> python
            // Android 需要 GSON  --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
            //
            String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
            HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
            Log.e("登录界面--->", res.toString());  //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}

            // 保存起来:cookies, localstorage
            // andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
            SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
            SharedPreferences.Editor editor= sharedPreferences.edit();
            editor.putString("token", res.token);
            editor.commit();

            // 跳转首页
            Intent in = new Intent(mcontext, IndexActivity.class);
            startActivity(in);


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

La diferencia entre los dos es:

  • El formato del formulario usa FormBody para construir el cuerpo de la solicitud.

  • El formato de cadena json usa tanto JSONObject como RequestBody para construir el cuerpo de la solicitud.

interceptor de solicitudes

Parte de la información del encabezado de la solicitud es transportada por cada solicitud HTTP. Esta información común del encabezado de la solicitud es implementada por el middleware en el marco del rastreador scrapy de python y por los interceptores de solicitudes en okhttp de la aplicación Android. El siguiente es el código de prueba simple de Interceptor.

// 4. 发送请求拦截器
Interceptor interceptor = new Interceptor() {
    @NonNull
    @Override
    public Response intercept(@NonNull Chain chain) throws IOException {
        String sign = "sfsadsadsa";
        // 请求还未发送,在请求体中增加了一个请求头
        Request request = chain.request().newBuilder().addHeader("x-gorgon", sign).build();
        Response response = chain.proceed(request);
        return response;
    }
};
new Thread() {
    @Override
    public void run() {
        // 加入拦截器
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
        // 构建请求体
        // FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();

        //JSONObject json = new JSONObject();
        //json.put("username", "dk");
        //json.put("password", "123");
        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());

        // form ---> post 请求体
        Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();      //  发送请求
            ResponseBody body = response.body();
            String resString = body.string();

            // Json反序列化,字符串转换成对象.
            // json.load(json字符串) --> python
            // Android 需要 GSON  --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
            //
            String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
            HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
            Log.e("登录界面--->", res.toString());  //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}

            // 保存起来:cookies, localstorage
            // andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
            SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
            SharedPreferences.Editor editor= sharedPreferences.edit();
            editor.putString("token", res.token);
            editor.commit();

            // 跳转首页
            Intent in = new Intent(mcontext, IndexActivity.class);
            startActivity(in);


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}.start();

La diferencia con el interceptor anterior :

  • Creó un interceptor antes de crear okhttp

  • Al crear okhttp, agregue un interceptor

NO_PROXY

Para evitar la captura de paquetes, algunas aplicaciones usarán el parámetro NO_PROXY de okhttp para prohibir que el teléfono Android configure un proxy del sistema. En este caso, puede usar la aplicación Drony para capturar paquetes sin un proxy, o puede usar aplicaciones como como Little Yellow Bird para capturar paquetes con una VPN local.

Para obtener información sobre la captura de paquetes sin agente, consulte: Análisis del rastreador de Python de la captura de paquetes en el modo sin agente de la aplicación y esquema de optimización antirrastreo para esto - Eeyhan - Blog Garden (cnblogs.com)


reacondicionar

Antes de usar la actualización, realice la siguiente configuración:

  • Introducción, implementación "com.squareup.retrofit2:retrofit:2.9.0" en build.gradle

El método de uso específico es el siguiente:

  1. Escribir interfaz, declarar solicitud de red

package com.example.liyang;

package com.example.liyang;

import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface HttpReq {
    // 向/api/v1/post 发送POST请求,表单格式 name=xx&pwd=xxx
    @POST("/api/v1/post")
    @FormUrlEncoded
    Call<ResponseBody> postLogin(@Field("name") String userName, @Field("pwd") String password);

    // 向/api/v2/xxx 发送GET请求,表单格式 ?age=xxx
    @GET("/api/v2/xxx")
    Call<ResponseBody> getInfo(@Query("age") String age);

    // 向/post/users 发送POST请求 json字符串格式 {name:xxxx,age:123}
    @POST("/post/users")
    Call<ResponseBody> postLoginJson(@Body RequestBody body);
}
  1. Llame a la interfaz, pase parámetros a la interfaz y envíe una solicitud

new Thread() {
    @Override
    public void run() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq httpRequest = retrofit.create(HttpReq.class);        
        
        // http://192.168.31.201:9999/api/v1/post  
        // name=xx&pwd=xxx
        Call<ResponseBody> call = httpRequest.postLogin("wupeiqi", "666");
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.i("登录", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
new Thread() {
    @Override
    public void run() {
        // http://192.168.31.201:9999/api/v2/xxx?age=123
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq req = retrofit.create(HttpReq.class);
        Call<ResponseBody> call = req.getInfo("123");
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.e("Retrofit返回的结果", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();
new Thread() {
    @Override
    public void run() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
        HttpReq httpRequest = retrofit.create(HttpReq.class);

        JSONObject json = new JSONObject(dataMap);
        String jsonString = json.toString();
        RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),jsonString);
        
        // http://192.168.31.201:9999/post/users  
        // {username:"root",password:"123456","sign":"xxxxdfsdfsdfsdfdfd"}
        Call<ResponseBody> call = httpRequest.postLoginJson(form);
        try {
            ResponseBody responseBody = call.execute().body();
            String responseString = responseBody.string();
            Log.i("登录", responseString);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}.start();

Precauciones:

  • Retrofit es una encapsulación adicional en okhttp. Se caracteriza por dividir la url solicitada en varios segmentos y especificarlos en diferentes lugares. La url se puede configurar de manera más flexible.

  • Al encontrar una interfaz escrita en retrofit, ya no se trata de encontrar la clase que la implementa, sino de encontrar la clase que la llama, empalmando la URL solicitada y encontrando los parámetros pasados.

  • El código es relativamente extenso y se centra en la forma de definir la interfaz, lo que determina el estilo de la solicitud, el método para llamar a la interfaz y los parámetros que se pasan. Las dos partes juntas determinan la URL de la solicitud.


GSON

Similar al módulo json en python, se usa para serializar objetos y deserializar cadenas json. Debe introducirse antes de usar Gson

implementation ‘com.google.code.gson:gson:2.8.6’
  • Serialización, objeto -> tipo de cadena

class HttpContext{
    public int code;
    public String message;
    
    public HttpContext(int code,String msg){
        this.code = code;
        this.message = msg;
    }
}
HttpContext obj = new HttpContext(1000,"成功");
String dataString = new Gson().toJson(obj); // '{"code":1000,"Message":"成功"}'
  • Deserialización, cadena -> objeto

// JSON格式
String dataString = "{\"status\": true, \"token\": \"fffk91234ksd\", \"name\": \"武沛齐\"}";
class HttpResponse{
    public boolean status;
    public String token;
    public String name;
}
HttpResponse obj = new Gson().fromJson(dataString,HttpResponse.class);
// obj.status  obj.name  obj.token
  • Si hay anidamiento de diccionarios al deserializar

String responseString = "{\"origin\": \"110.248.149.62\",\"url\": \"https://www.httpbin.org/post\",\"dataList\":[{\"id\":1,\"name\":\"一个小黑\"},{\"id\":2,\"name\":\"eric\"}]}";
class Item {
    public int id;
    public String name;
}
public class HttpResponse {
    public String url;
    public String origin;
    public ArrayList<Item> dataList;
}
HttpResponse obj = new Gson().fromJson(dataString, HttpResponse.class);
// obj.url  obj.origin
Item objItem = obj.dataList.get(1);
// objItem.name

Guardar en archivo XML

Guardar en ubicación en el teléfono:

/data/data/com.example.liyang/shared_prefs/sp_city.xml

guardar token

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("token","111111");
editor.commit();

eliminar token

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove("token");
editor.commit();

ficha de lectura

SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
String token = sp.getString("token","");
  • Recuerde que el objeto SharedPreferences se usa para leer y escribir el archivo XML local de la aplicación móvil

  • Los archivos XML son muy similares a las cookies, ya sea generados por un algoritmo local o devueltos por un servidor de solicitudes HTTP.


Resumir

jadx, jeb para descompilar el código de Android:

  • búsqueda por palabra clave

  • Consultar paso a paso según el proceso solicitado

  • llamada java

Nota: La pequeña aplicación puede revertirlo por completo al comprender el contenido anterior.

Supongo que te gusta

Origin blog.csdn.net/m0_57126939/article/details/128849769
Recomendado
Clasificación