728x90
반응형

https://www.youtube.com/watch?v=BAkGm02WBc0&list=PLaqXbTT0YCZGlZ6G7puu189Jz3XDAW7kx&index=1 

위 영상을 참고로 제작

 

프로젝트 생성 및 paho 라이브러리 설치

MQTT_publish라는 이름의 새로운 프로젝트 생성

 

build.gradle에 아래 코드를 추가

repositories {
    maven {
    	url "https://repo.eclipse.org/content/repositories/paho-releases/"
    }
}

depandencies {
	compile('org.eclipse.paho:org.eclipse.paho.android.service:1.0.2') {
        exclude module: 'support-v4'
    }
    ...
}

 

첫번째 코드는 paho라는 mqtt repository를 추가하고

두번째 코드는 paho 서비스 depandency를 앱에 추가한다

 

이후 external libraries에서 두개가 추가된 것을 확인할 수 있다

 

 AndroidManifest.xml의 <application> 태그 위에 권한 설정 코드 추가

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

 

마지막으로<application> 태그 안에 아래 코드를 추가

<service android:name="org.eclipse.paho.android.service.MqttService" >
</service>

 

MainActivity.java 코드 작성

아래 코드를 추가하고 import를 모두 추가해준다

package com.example.mqtt_publish;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;

import static android.content.ContentValues.TAG;

public class MainActivity extends AppCompatActivity {

    static String MQTTHOST = "IP_ADDRESS";
    static String USERNAME = "";
    static String PASSWORD = "";
    String pubTopic = "test";

    MqttAndroidClient client;

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

        String clientId = MqttClient.generateClientId();
        client = new MqttAndroidClient(this.getApplicationContext(), MQTTHOST, clientId);

        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(USERNAME);
        options.setPassword(PASSWORD.toCharArray());


        try {
            IMqttToken token = client.connect(options);
            token.setActionCallback(new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Toast.makeText(MainActivity.this, "connected", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Toast.makeText(MainActivity.this, "connection failed", Toast.LENGTH_SHORT).show();
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    public void pub(View v)
    {
        String topic = pubTopic;
        String message = "hello";
        try {
            client.publish(topic, message.getBytes(), 0, false);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }
}
더보기

MQTT broker의 주소와 접속할 USERNAME, PASSWORD 선언

publish할 topic 선언

MqttAndroidClient 전역변수 선언

 

clientID를 생성하고 MQTT broker에 접속할 client 생성

연결 옵션 설정

 

연결 여부에 따른 Toast 메세지 팝업

 

메세지 publish 함수

 

 

Publish 버튼 추가

버튼을 추가하고 상하좌우로 체인은 연결한 뒤 text와 onClick를 설정

그리고 앱을 빌드해봤다

 

오류

더보기
07/11 17:47:34: Launching 'app' on Nexus 5 API 22.
Install successfully finished in 5 s 845 ms.
$ adb shell am start -n "com.example.mqtt_publish/com.example.mqtt_publish.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 5721 on device 'Nexus_5_API_22 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/art: Not late-enabling -Xcheck:jni (already on)
W/System: ClassLoader referenced unknown path: /data/app/com.example.mqtt_publish-1/lib/x86_64
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter androidx.vectordrawable.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
I/art: Background partial concurrent mark sweep GC freed 15904(1124KB) AllocSpace objects, 9(320KB) LOS objects, 39% free, 2MB/4MB, paused 17.009ms total 54.046ms
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.mqtt_publish, PID: 5721
    java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/content/LocalBroadcastManager;
        at org.eclipse.paho.android.service.MqttAndroidClient.registerReceiver(MqttAndroidClient.java:450)
        at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:428)
        at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:334)
        at com.example.mqtt_publish.MainActivity.onCreate(MainActivity.java:43)
        at android.app.Activity.performCreate(Activity.java:6237)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
        at android.app.ActivityThread.-wrap11(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.content.LocalBroadcastManager" on path: DexPathList[[zip file "/data/app/com.example.mqtt_publish-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.mqtt_publish-1/lib/x86_64, /vendor/lib64, /system/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        at org.eclipse.paho.android.service.MqttAndroidClient.registerReceiver(MqttAndroidClient.java:450) 
        at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:428) 
        at org.eclipse.paho.android.service.MqttAndroidClient.connect(MqttAndroidClient.java:334) 
        at com.example.mqtt_publish.MainActivity.onCreate(MainActivity.java:43) 
        at android.app.Activity.performCreate(Activity.java:6237) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
        at android.app.ActivityThread.-wrap11(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:5417) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
    	Suppressed: java.lang.ClassNotFoundException: android.support.v4.content.LocalBroadcastManager
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
        		... 17 more
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

분명 영상을 그래도 따라했는데 위와 같은 오류가 나오면서 앱이 튕긴다...

여러가지를 시도해봤다

 

 

1. 아래 코드를 추가해보자 https://github.com/firebase/quickstart-unity/issues/402

implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'

오류 그대로...

 

2. 아래 코드를 추가해보자 https://github.com/AltBeacon/android-beacon-library/issues/919

implementation 'com.android.support:localbroadcastmanager:28.0.0'

실패

 

3. 저번에 썼던 방법으로 해보자

complie 부분을 아래와 같이 교체

implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'

실패...

 

4. 아래 코드를 추가 https://stackoverflow.com/questions/45696559/java-lang-noclassdeffounderror-failed-resolution-of-landroid-support-v4-conten/45696721

implementation 'androidx.legacy:legacy-support-v4:1.0.0'

되는게 없네

 

5. 아래 코드를 추가하고 Migrate to AndroidX

https://stackoverflow.com/questions/45696559/java-lang-noclassdeffounderror-failed-resolution-of-landroid-support-v4-conten/45696721

implementation group: 'com.android.support', name: 'support-v4', version: '28.0.0'

성공...

 

코드 수정

package com.example.mqtt_publish;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;

public class MainActivity extends AppCompatActivity {

    static String MQTTHOST = "broker.mqtt.com";
    static String USERNAME = "";
    static String PASSWORD = "";
    String pubTopic = "test";

    MqttAndroidClient client;

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

        String clientId = MqttClient.generateClientId();
        client = new MqttAndroidClient(this.getApplicationContext(), MQTTHOST, clientId);

        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName(USERNAME);
        options.setPassword(PASSWORD.toCharArray());


        try {
            //IMqttToken token = client.connect();
            IMqttToken token = client.connect(options);
            token.setActionCallback(new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Toast.makeText(MainActivity.this, "connected", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Toast.makeText(MainActivity.this, "connection failed", Toast.LENGTH_SHORT).show();
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    public void pub(View v)
    {
        String topic = pubTopic;
        String message = "hello";
        try {
            client.publish(topic, message.getBytes(), 0, false);
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }
}

이제 튕기지는 않는데... 계속 연결이 되지 않는다...

 

유튜브 댓글과 영상에 나온 블로그(?), 구글링을 통해 아래와 같이 변수 부분을 조금 수정했다

    static String MQTTHOST = "tcp://192.168.1.104:1883";
    static String USERNAME = "test";
    static String PASSWORD = "test";

tcp://와 :1883를 추가하고

USERNAME과 PASSWORD에 아무거나 넣어줬다. 왜인지 공백으로 두면 안된다...

 

앱을 빌드해보면 connection failed가 뜬다..?

MQTT broker를 안켰구나

 

MQTT broker에서 확인

mosquitto로 MQTT broker를 시작한다음 앱을 실행

connected가 뜨는 것을 확인했다

 

이제 버튼을 누르면...!

publish 성공!