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

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui