Anonymous
Intergrate Android MQTT Plugin AAR in Unity - Vordergrunddienst [geschlossen]
Post
by Anonymous » 25 Aug 2025, 16:59
Ich versuche, Code im Hintergrund auf Android für ein Einheitsprojekt auszuführen. Da Unity nicht direkt Hintergrunddienste zulässt, habe ich eine Android -Bibliothek (AAR) erstellt und sie in Unity integriert. Dort funktioniert es korrekt. modules androidManifest.xml. Plugin. < /p>
Der Code und die Abhängigkeiten funktionieren in der eigenständigen App. Einheit?
Code: Select all
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "com.beezy.mqttlib"
compileSdk = 34
defaultConfig {
minSdk = 24
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation("org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5")
implementation("org.eclipse.paho:org.eclipse.paho.android.service:1.1.1")
implementation ("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
}
< /code>
Modul des Moduls < /p>
< /code>
FORECORGMQTTService.java
package com.beezy.mqttlib;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.ArrayList;
public class ForegroundMqttService extends Service {
private static final String TAG = "ForegroundMqttService";
private static final String CHANNEL_ID = "MQTTServiceChannel";
private static final String BROKER_URI = "tcp://broker.hivemq.com:1883";
// Service States
private enum ServiceState { CONNECTED, DISCONNECTED, STOPPED }
private ServiceState currentState = ServiceState.STOPPED;
private MqttAndroidClient mqttClient;
private ArrayList subscribedTopics = new ArrayList();
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "MQTT Foreground Service", NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) manager.createNotificationChannel(channel);
}
}
private Notification buildNotification(String content) {
Intent stopIntent = new Intent(this, ForegroundMqttService.class).setAction("ACTION_STOP");
PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Beezy MQTT Service")
.setContentText(content)
.setSmallIcon(R.drawable.ic_notification)
.setOngoing(true)
.addAction(R.drawable.ic_notification, "Stop", stopPendingIntent)
.build();
}
private void updateNotification(String text) {
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) manager.notify(1, buildNotification(text));
}
private void notifyActivityStatus(String status) {
Intent intent = new Intent("MQTT_EVENTS");
intent.putExtra("subscribed", false);
intent.putExtra("statusText", status);
sendBroadcast(intent);
}
private void initMqttClient() {
if (mqttClient != null && (mqttClient.isConnected() || mqttClient.isConnected())) return;
String clientId = MqttClient.generateClientId();
mqttClient = new MqttAndroidClient(getApplicationContext(), BROKER_URI, clientId);
mqttClient.setCallback(new MqttCallbackExtended() {
@Override
public void connectComplete(boolean reconnect, String serverURI) {
currentState = ServiceState.CONNECTED;
updateNotification("Connected to broker");
notifyActivityStatus("Connected & Subscribed");
resubscribeAllTopics();
}
@Override
public void connectionLost(Throwable cause) {
if (currentState != ServiceState.STOPPED && currentState != ServiceState.DISCONNECTED) {
currentState = ServiceState.DISCONNECTED;
updateNotification("Connection lost. Reconnecting...");
notifyActivityStatus("Connection lost. Reconnecting...");
}
}
@Override
public void messageArrived(String topic, MqttMessage message) {
String payload = new String(message.getPayload());
updateNotification("Last msg: " + payload);
handleMqttPayload(payload);
// Send broadcast to activity
Intent intent = new Intent("MQTT_EVENTS");
intent.putExtra("payload", payload);
sendBroadcast(intent);
}
private void handleMqttPayload(String payload) {
// Split into sections by %
String[] parts = payload.split("%");
// Just for debugging – you’ll see all parts
for (int i = 0; i < parts.length; i++) {
Log.d("MQTT_PART", "Index " + i + ": " + parts[i]);
}
// The "false/true" flag is always at index 2 of the last block:
// Example last block: "step0", "false", "prog0", "dates0|0", "sec-1", "2"
// So index of "false"/"true" is always parts[length-5] (based on your example).
if (parts.length > 2) {
String flag = parts[5]; // = Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createOneShot(
150, // vibration duration in ms
VibrationEffect.DEFAULT_AMPLITUDE
));
} else {
vibrator.vibrate(150); // deprecated but works on older devices
}
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {}
});
}
private void connectToBroker() {
if (mqttClient == null) initMqttClient();
if (mqttClient.isConnected() || mqttClient.isConnected()) return;
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setAutomaticReconnect(true);
try {
mqttClient.connect(options, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken asyncActionToken) {
currentState = ServiceState.CONNECTED;
updateNotification("Connected to broker");
resubscribeAllTopics();
}
@Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(TAG, "Connection failed: " + exception.getMessage());
updateNotification("Connection failed. Retrying...");
currentState = ServiceState.DISCONNECTED;
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
private void resubscribeAllTopics() {
if (mqttClient != null && mqttClient.isConnected()) {
for (String topic : subscribedTopics) {
try {
mqttClient.subscribe(topic, 1);
} catch (MqttException e) {
Log.e(TAG, "Failed to subscribe to topic: " + topic);
}
}
Intent subIntent = new Intent("MQTT_EVENTS");
subIntent.putExtra("subscribed", true);
sendBroadcast(subIntent);
}
}
private void disconnectMqttOnly() {
try {
if (mqttClient != null && mqttClient.isConnected()) {
mqttClient.disconnect();
updateNotification("MQTT disconnected, service running");
notifyActivityStatus("Disconnected from MQTT");
}
} catch (MqttException e) {
e.printStackTrace();
}
}
private void stopAndDestroyService() {
currentState = ServiceState.STOPPED;
notifyActivityStatus("Service stopped");
if (mqttClient != null) {
try {
if (mqttClient.isConnected()) mqttClient.disconnect();
mqttClient.close();
} catch (Exception e) {
Log.e(TAG, "Error disconnecting MQTT client: " + e.getMessage());
}
}
stopSelf();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null) {
// Retrieve the topics list from the intent
ArrayList topicsFromIntent = intent.getStringArrayListExtra("topics");
if (topicsFromIntent != null) {
subscribedTopics = topicsFromIntent;
}
switch (intent.getAction()) {
case "ACTION_START":
startServiceAndConnect();
break;
case "ACTION_DISCONNECT":
if (currentState == ServiceState.STOPPED) {
startServiceAndDoNotConnect();
} else if (currentState == ServiceState.CONNECTED) {
currentState = ServiceState.DISCONNECTED;
disconnectMqttOnly();
updateNotification("Service running (not connected)");
notifyActivityStatus("Service running (not connected)");
}
break;
case "ACTION_STOP":
stopAndDestroyService();
break;
case "ACTION_SUBSCRIBE":
String topic = intent.getStringExtra("topic");
if (topic != null && !subscribedTopics.contains(topic)) {
subscribedTopics.add(topic);
subscribeToTopic(topic);
}
break;
case "ACTION_UNSUBSCRIBE":
String unsubscribeTopic = intent.getStringExtra("topic");
subscribedTopics.remove(unsubscribeTopic);
break;
}
} else {
// First launch scenario or no intent data
startServiceAndConnect();
}
return START_STICKY;
}
private void startServiceAndConnect() {
initMqttClient();
connectToBroker();
startForeground(1, buildNotification("Connecting..."));
}
private void startServiceAndDoNotConnect() {
initMqttClient();
currentState = ServiceState.DISCONNECTED;
updateNotification("Service running (not connected)");
notifyActivityStatus("Service running (not connected)");
startForeground(1, buildNotification("Service running (not connected)"));
}
private void subscribeToTopic(String topic) {
try {
if (mqttClient != null && mqttClient.isConnected()) {
mqttClient.subscribe(topic, 1);
}
} catch (MqttException e) {
Log.e(TAG, "Failed to subscribe: " + topic, e);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
stopAndDestroyService();
}
}
1756133956
Anonymous
Ich versuche, Code im Hintergrund auf Android für ein Einheitsprojekt auszuführen. Da Unity nicht direkt Hintergrunddienste zulässt, habe ich eine Android -Bibliothek (AAR) erstellt und sie in Unity integriert. Dort funktioniert es korrekt. modules androidManifest.xml. Plugin. < /p> Der Code und die Abhängigkeiten funktionieren in der eigenständigen App. Einheit?[code]plugins { alias(libs.plugins.android.library) } android { namespace = "com.beezy.mqttlib" compileSdk = 34 defaultConfig { minSdk = 24 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } } dependencies { implementation(libs.appcompat) implementation(libs.material) implementation("org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5") implementation("org.eclipse.paho:org.eclipse.paho.android.service:1.1.1") implementation ("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0") testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) } < /code> Modul des Moduls < /p> < /code> FORECORGMQTTService.java package com.beezy.mqttlib; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.IBinder; import android.os.VibrationEffect; import android.os.Vibrator; import android.util.Log; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import org.eclipse.paho.android.service.MqttAndroidClient; import org.eclipse.paho.client.mqttv3.IMqttActionListener; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.IMqttToken; import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import java.util.ArrayList; public class ForegroundMqttService extends Service { private static final String TAG = "ForegroundMqttService"; private static final String CHANNEL_ID = "MQTTServiceChannel"; private static final String BROKER_URI = "tcp://broker.hivemq.com:1883"; // Service States private enum ServiceState { CONNECTED, DISCONNECTED, STOPPED } private ServiceState currentState = ServiceState.STOPPED; private MqttAndroidClient mqttClient; private ArrayList subscribedTopics = new ArrayList(); private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "MQTT Foreground Service", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) manager.createNotificationChannel(channel); } } private Notification buildNotification(String content) { Intent stopIntent = new Intent(this, ForegroundMqttService.class).setAction("ACTION_STOP"); PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); return new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Beezy MQTT Service") .setContentText(content) .setSmallIcon(R.drawable.ic_notification) .setOngoing(true) .addAction(R.drawable.ic_notification, "Stop", stopPendingIntent) .build(); } private void updateNotification(String text) { NotificationManager manager = getSystemService(NotificationManager.class); if (manager != null) manager.notify(1, buildNotification(text)); } private void notifyActivityStatus(String status) { Intent intent = new Intent("MQTT_EVENTS"); intent.putExtra("subscribed", false); intent.putExtra("statusText", status); sendBroadcast(intent); } private void initMqttClient() { if (mqttClient != null && (mqttClient.isConnected() || mqttClient.isConnected())) return; String clientId = MqttClient.generateClientId(); mqttClient = new MqttAndroidClient(getApplicationContext(), BROKER_URI, clientId); mqttClient.setCallback(new MqttCallbackExtended() { @Override public void connectComplete(boolean reconnect, String serverURI) { currentState = ServiceState.CONNECTED; updateNotification("Connected to broker"); notifyActivityStatus("Connected & Subscribed"); resubscribeAllTopics(); } @Override public void connectionLost(Throwable cause) { if (currentState != ServiceState.STOPPED && currentState != ServiceState.DISCONNECTED) { currentState = ServiceState.DISCONNECTED; updateNotification("Connection lost. Reconnecting..."); notifyActivityStatus("Connection lost. Reconnecting..."); } } @Override public void messageArrived(String topic, MqttMessage message) { String payload = new String(message.getPayload()); updateNotification("Last msg: " + payload); handleMqttPayload(payload); // Send broadcast to activity Intent intent = new Intent("MQTT_EVENTS"); intent.putExtra("payload", payload); sendBroadcast(intent); } private void handleMqttPayload(String payload) { // Split into sections by % String[] parts = payload.split("%"); // Just for debugging – you’ll see all parts for (int i = 0; i < parts.length; i++) { Log.d("MQTT_PART", "Index " + i + ": " + parts[i]); } // The "false/true" flag is always at index 2 of the last block: // Example last block: "step0", "false", "prog0", "dates0|0", "sec-1", "2" // So index of "false"/"true" is always parts[length-5] (based on your example). if (parts.length > 2) { String flag = parts[5]; // = Build.VERSION_CODES.O) { vibrator.vibrate(VibrationEffect.createOneShot( 150, // vibration duration in ms VibrationEffect.DEFAULT_AMPLITUDE )); } else { vibrator.vibrate(150); // deprecated but works on older devices } } } @Override public void deliveryComplete(IMqttDeliveryToken token) {} }); } private void connectToBroker() { if (mqttClient == null) initMqttClient(); if (mqttClient.isConnected() || mqttClient.isConnected()) return; MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setAutomaticReconnect(true); try { mqttClient.connect(options, null, new IMqttActionListener() { @Override public void onSuccess(IMqttToken asyncActionToken) { currentState = ServiceState.CONNECTED; updateNotification("Connected to broker"); resubscribeAllTopics(); } @Override public void onFailure(IMqttToken asyncActionToken, Throwable exception) { Log.e(TAG, "Connection failed: " + exception.getMessage()); updateNotification("Connection failed. Retrying..."); currentState = ServiceState.DISCONNECTED; } }); } catch (MqttException e) { e.printStackTrace(); } } private void resubscribeAllTopics() { if (mqttClient != null && mqttClient.isConnected()) { for (String topic : subscribedTopics) { try { mqttClient.subscribe(topic, 1); } catch (MqttException e) { Log.e(TAG, "Failed to subscribe to topic: " + topic); } } Intent subIntent = new Intent("MQTT_EVENTS"); subIntent.putExtra("subscribed", true); sendBroadcast(subIntent); } } private void disconnectMqttOnly() { try { if (mqttClient != null && mqttClient.isConnected()) { mqttClient.disconnect(); updateNotification("MQTT disconnected, service running"); notifyActivityStatus("Disconnected from MQTT"); } } catch (MqttException e) { e.printStackTrace(); } } private void stopAndDestroyService() { currentState = ServiceState.STOPPED; notifyActivityStatus("Service stopped"); if (mqttClient != null) { try { if (mqttClient.isConnected()) mqttClient.disconnect(); mqttClient.close(); } catch (Exception e) { Log.e(TAG, "Error disconnecting MQTT client: " + e.getMessage()); } } stopSelf(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null && intent.getAction() != null) { // Retrieve the topics list from the intent ArrayList topicsFromIntent = intent.getStringArrayListExtra("topics"); if (topicsFromIntent != null) { subscribedTopics = topicsFromIntent; } switch (intent.getAction()) { case "ACTION_START": startServiceAndConnect(); break; case "ACTION_DISCONNECT": if (currentState == ServiceState.STOPPED) { startServiceAndDoNotConnect(); } else if (currentState == ServiceState.CONNECTED) { currentState = ServiceState.DISCONNECTED; disconnectMqttOnly(); updateNotification("Service running (not connected)"); notifyActivityStatus("Service running (not connected)"); } break; case "ACTION_STOP": stopAndDestroyService(); break; case "ACTION_SUBSCRIBE": String topic = intent.getStringExtra("topic"); if (topic != null && !subscribedTopics.contains(topic)) { subscribedTopics.add(topic); subscribeToTopic(topic); } break; case "ACTION_UNSUBSCRIBE": String unsubscribeTopic = intent.getStringExtra("topic"); subscribedTopics.remove(unsubscribeTopic); break; } } else { // First launch scenario or no intent data startServiceAndConnect(); } return START_STICKY; } private void startServiceAndConnect() { initMqttClient(); connectToBroker(); startForeground(1, buildNotification("Connecting...")); } private void startServiceAndDoNotConnect() { initMqttClient(); currentState = ServiceState.DISCONNECTED; updateNotification("Service running (not connected)"); notifyActivityStatus("Service running (not connected)"); startForeground(1, buildNotification("Service running (not connected)")); } private void subscribeToTopic(String topic) { try { if (mqttClient != null && mqttClient.isConnected()) { mqttClient.subscribe(topic, 1); } } catch (MqttException e) { Log.e(TAG, "Failed to subscribe: " + topic, e); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); stopAndDestroyService(); } } [/code]