java、python混合编程:Android调用python编写的API接口并实现数据通信

一、前言

​ 每种计算机语言都有自己的过人之处,java适合Android开发、大数据处理,python适合做机器视觉、人工智能,但是如果我们想要完成一些强大的功能时,仅仅使用一种计算机语言肯定不能轻易满足我们的需求,如果可以将不同的语言混合使用,我们就可以利用各个语言的强项来实现我们所需的不同的功能。

​ 移动互联网时代,手机已经已经成为我们必备的设备,如果能有一个功能强大的手机app将极大地便利我们的生活。但是网上并没有详细的教程实现在android中使用python接口,要么就是博客时间久远不适用现在,要么就是一篇水文浪费大家时间。下面我将在Android开发中调用python编写的API接口进行数据通信

二、准备

本人的开发环境如下:
环境配置
本项目的目录结构如下:
请添加图片描述

三、编写Python代码

创建一个Python项目,创建androidAPI.py和SSL.py,将下列代码粘贴进去:

  • SSL.py:
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
import datetime

# 生成私钥
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# 创建证书主题
subject = issuer = x509.Name([
    x509.NameAttribute(NameOID.COMMON_NAME, u"example.com"),
    x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Organization"),
])

# 生成证书
cert = x509.CertificateBuilder().subject_name(
    subject
).issuer_name(
    issuer
).public_key(
    private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.datetime.utcnow()
).not_valid_after(
    datetime.datetime.utcnow() + datetime.timedelta(days=365)
).add_extension(
    x509.SubjectAlternativeName([x509.DNSName(u"example.com")]),
    critical=False,
).sign(private_key, hashes.SHA256(), default_backend())

# 保存私钥和证书
with open("private.key", "wb") as f:
    f.write(private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption()
    ))

with open("certificate.crt", "wb") as f:
    f.write(cert.public_bytes(serialization.Encoding.PEM))

print("证书和私钥已生成。")

这段代码负责创建一个自签名的SSL证书,当执行完成之后,会在当下目录生成签名文件和秘钥文件。
请添加图片描述

  • androidAPI.py:
from flask import Flask, request, jsonify
from flask_sslify import SSLify
import cv2 as cv

app = Flask(__name__)
sslify = SSLify(app)
# 示例数据
data = {
    "message": "hello,my friend",
    "status": "success"
}

message = "ni hao"


# 根路由
@app.route('/')
def home():
    return "Welcome to the Python API"


# 示例接口
@app.route('/api/get_message', methods=['GET'])
def get_message():
    image = cv.imread(r"C:\Users\18388\Desktop\7ae9758d7aa0c9d818f3567310b347e.jpg", 0)
    gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    return gray_image


# 接受POST请求的接口
@app.route('/api/post_data', methods=['POST'])
def post_data():
    received_data = request.json
    return jsonify({"received_data": received_data, "status": "data received"})


if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000, ssl_context=(r'.\certificate.crt', r'.\private.key'))

我们使用了flask接口,创建了两个对外的web接口,分别是get_message()和post_data()。运行后,会控制板上会出现我们搭建的web端口和ip地址。这两个都是本机地址,一样的。我们此次采用的是https协议,方便映射到外网。
请添加图片描述

四、编写android代码

  • 添加网络请求权限:

    我们创建一个android项目,在AndroidManifest.xml中添加网络请求权限代码。

<uses-permission android:name="android.permission.INTERNET" />
  • 添加maven仓库和okhttp网络请求库:

android新版本中,需要在settings.gradle中添加jetpack组件库。

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

maven仓库配置好后,在build.gradle中的dependencies中添加

implementation 'com.squareup.okhttp3:okhttp:3.14.+'

请添加图片描述

  • 编写Python.java:

新建一个EmptyActivity,贴入以下代码:

package com.example.modbustcp.python;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.modbustcp.R;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;

public class Python extends AppCompatActivity {

    //忽略证书不安全错误
    private OkHttpClient client = new OkHttpClient.Builder()
            .sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
            .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
            .build();


    Button button;
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_python2);

        button = findViewById(R.id.button1);
        textView = findViewById(R.id.textView1);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 发送GET请求
                sendGetRequest();


            }
        });
    }

    private void sendGetRequest() {
        String url = "https://115.236.153.172:56631/api/get_message";
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("获取请求失败");
                    }
                });
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (response.isSuccessful()) {
                    final String responseData = response.body().string();
                    runOnUiThread(new Runnable() {
                        @SuppressLint("SetTextI18n")
                        @Override
                        public void run() {
                            // 处理响应数据
                            Log.d("获取数据:", responseData);
                            textView.setText("数据为:" + responseData);
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText("响应失败");
                        }
                    });
                }
            }
        });
    }

    //发送post请求
    private void sendPostRequest() {
        String url = "http://115.236.153.172:24529/api/post_data";
        MediaType JSON = MediaType.get("application/json; charset=utf-8");

        // 示例数据
        String json = "{\"name\": \"John\", \"age\": 30}";

        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("获取失败");
                        textView.setText(e.getMessage());
                        System.out.println("获取失败的原因是"+e.getMessage());
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    final String responseData = response.body().string();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            // 处理响应数据
                            Log.d("POST Response", responseData);
                            textView.setText("数据为:" + responseData);
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText("响应失败");
                        }
                    });
                }
            }
        });
    }

}

修改好端口和ip地址,便可以实现http通信了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值