Android studio 呼叫盒app

一、权限文件

0.gradle切换国内源

#Fri Nov 08 15:46:05 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

1.添加仅测试声明,针对vivo手机安装不上app

android.injected.testOnly=false

2.添加弹窗块的代码

    implementation("androidx.appcompat:appcompat:1.6.1")

3.申请使用网络权限

    <!-- 申请网络权限 -->
    <uses-permission android:name="android.permission.INTERNET"/>

二、前端UI布局

1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 按钮和灯的布局 -->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_centerInParent="true">

        <!-- 按钮1 -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical"
            android:layout_marginBottom="16dp">

            <View
                android:id="@+id/light1"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginEnd="10dp"
                android:background="@android:color/darker_gray" />

            <Button
                android:id="@+id/button1"
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:text="1"
                android:backgroundTint="@android:color/darker_gray"
                android:textColor="@android:color/white" />
        </LinearLayout>

        <!-- 按钮2 -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical"
            android:layout_marginBottom="16dp">

            <View
                android:id="@+id/light2"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginEnd="10dp"
                android:background="@android:color/darker_gray" />

            <Button
                android:id="@+id/button2"
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:text="2"
                android:backgroundTint="@android:color/darker_gray"
                android:textColor="@android:color/white" />
        </LinearLayout>

        <!-- 按钮3 -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical"
            android:layout_marginBottom="16dp">

            <View
                android:id="@+id/light3"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginEnd="10dp"
                android:background="@android:color/darker_gray" />

            <Button
                android:id="@+id/button3"
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:text="3"
                android:backgroundTint="@android:color/darker_gray"
                android:textColor="@android:color/white" />
        </LinearLayout>

        <!-- 按钮4 -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical">

            <View
                android:id="@+id/light4"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_marginEnd="10dp"
                android:background="@android:color/darker_gray" />

            <Button
                android:id="@+id/button4"
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:text="4"
                android:backgroundTint="@android:color/darker_gray"
                android:textColor="@android:color/white" />
        </LinearLayout>
    </LinearLayout>

    <!-- 设置按钮 -->
    <Button
        android:id="@+id/settingsButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="设置"
        android:backgroundTint="@android:color/darker_gray"
        android:textColor="@android:color/white"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="16dp" />
</RelativeLayout>

2.dialog_settings.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- 目标 IP -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="目标 IP:" />
    <EditText
        android:id="@+id/targetIp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入目标 IP"
        android:inputType="text" />

    <!-- 目标端口 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="目标端口:"
        android:layout_marginTop="8dp" />
    <EditText
        android:id="@+id/targetPort"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入目标端口"
        android:inputType="number" />

    <!-- 本地端口 -->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="本地端口:"
        android:layout_marginTop="8dp" />
    <EditText
        android:id="@+id/localPort"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入本地端口"
        android:inputType="number" />
</LinearLayout>

三、后端文件

MainActivity.java

package com.example.fl;

import android.app.AlertDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class MainActivity extends AppCompatActivity {

    private String targetIp = "192.168.0.229"; // 默认目标 IP
    private int targetPort = 10000; // 默认目标端口
    private int localPort = 55555; // 默认本地端口49200-65535
    private DatagramSocket socket;

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

        // 从 SharedPreferences 中读取保存的设置
        SharedPreferences preferences = getSharedPreferences("UDPSettings", MODE_PRIVATE);
        targetIp = preferences.getString("targetIp", "192.168.0.229"); // 默认值
        targetPort = preferences.getInt("targetPort", 10000); // 默认值
        localPort = preferences.getInt("localPort", 55555); // 默认值

        initializeSocket();

        setupButtonAndLight(R.id.button1, R.id.light1, "1");
        setupButtonAndLight(R.id.button2, R.id.light2, "2");
        setupButtonAndLight(R.id.button3, R.id.light3, "3");
        setupButtonAndLight(R.id.button4, R.id.light4, "4");

        Button settingsButton = findViewById(R.id.settingsButton);
        settingsButton.setOnClickListener(v -> openSettingsDialog());
    }


    private void initializeSocket() {
        try {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
            socket = new DatagramSocket(localPort);
            new Thread(this::receiveUDPMessage).start();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "Socket 初始化失败,请检查本地端口设置", Toast.LENGTH_SHORT).show();
        }
    }

    private void setupButtonAndLight(int buttonId, int lightId, String message) {
        Button button = findViewById(buttonId);
        View light = findViewById(lightId);

        button.setOnClickListener(v -> {
            sendUDPMessage(message, success -> {
                if (success) {
                    runOnUiThread(() -> light.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light)));
                } else {
                    runOnUiThread(() -> Toast.makeText(this, "发送失败", Toast.LENGTH_SHORT).show());
                }
            });
        });
    }

    private void sendUDPMessage(String message, UDPResponseCallback callback) {
        new Thread(() -> {
            boolean success = false;
            try {
                InetAddress address = InetAddress.getByName(targetIp);
                DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), address, targetPort);
                socket.send(packet);
                success = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            callback.onResponse(success);
        }).start();
    }

    private void receiveUDPMessage() {
        byte[] buffer = new byte[1024];
        while (true) {
            try {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);
                String received = new String(packet.getData(), 0, packet.getLength());
                runOnUiThread(() -> handleReceivedMessage(received));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void handleReceivedMessage(String message) {
        int lightId;
        switch (message) {
            case "1":
                lightId = R.id.light1;
                break;
            case "2":
                lightId = R.id.light2;
                break;
            case "3":
                lightId = R.id.light3;
                break;
            case "4":
                lightId = R.id.light4;
                break;
            default:
                return;
        }

        View light = findViewById(lightId);
        light.setBackgroundColor(getResources().getColor(android.R.color.darker_gray));
    }

    private void openSettingsDialog() {
        View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_settings, null);
        EditText ipInput = dialogView.findViewById(R.id.targetIp);
        EditText portInput = dialogView.findViewById(R.id.targetPort);
        EditText localPortInput = dialogView.findViewById(R.id.localPort);

        // 获取 SharedPreferences 保存的数据
        SharedPreferences preferences = getSharedPreferences("UDPSettings", MODE_PRIVATE);
        ipInput.setText(preferences.getString("targetIp", targetIp));
        portInput.setText(String.valueOf(preferences.getInt("targetPort", targetPort)));
        localPortInput.setText(String.valueOf(preferences.getInt("localPort", localPort)));

        new AlertDialog.Builder(this)
                .setTitle("设置目标和本地端口")
                .setView(dialogView)
                .setPositiveButton("保存", (dialog, which) -> {
                    targetIp = ipInput.getText().toString();
                    targetPort = Integer.parseInt(portInput.getText().toString());
                    localPort = Integer.parseInt(localPortInput.getText().toString());

                    // 保存设置到 SharedPreferences
                    SharedPreferences.Editor editor = preferences.edit();
                    editor.putString("targetIp", targetIp);
                    editor.putInt("targetPort", targetPort);
                    editor.putInt("localPort", localPort);
                    editor.apply();

                    initializeSocket(); // 更新本地端口后重新初始化 Socket
                    Toast.makeText(this, "设置已保存", Toast.LENGTH_SHORT).show();
                })
                .setNegativeButton("取消", null)
                .show();
    }


    // 定义回调接口
    private interface UDPResponseCallback {
        void onResponse(boolean success);
    }
}

四、实现效果

app按下1234 绿色led亮 目标设备收到数据

回传本地IP和端口 1

led1 灯灭

链接: https://pan.baidu.com/s/1x46I-dhMG_2mRchokZ0xiA?pwd=ktam 提取码: ktam

相关推荐
带电的小王1 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡1 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道1 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
paintstar2 小时前
vscode 快速切换cangjie版本
ide·vscode·编辑器·仓颉·cangjie
科协软件20182 小时前
vscode+latex快捷键
ide·vscode·编辑器
阿甘知识库2 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
cnnews3 小时前
在vscode中的ESP-IDF插件中使用Arduino框架作为组件
ide·vscode·编辑器
元争栈道3 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe3 小时前
Android Hook - 动态加载so库
android
居居飒4 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin