如何在Android Studio中调用.so库中的方法

8

编辑:请参见我的第一个答案。

我想在我的项目中使用Android串口API。但我遇到了很多麻烦。关于如何配置旧版本的gradle或如何使用NDK编译有大量相互冲突的信息,这两者都没有用处。我完全迷失了方向。

唯一我找到的可能正确的步骤如下:

进展 #1. 我将 libserial_port.so 放置在 src/main/jnilibs/armeabi 中。当我将其作为 zip 文件打开时,它出现在 apk 中。

但是我该如何告诉编译器使用此库?如何告诉它将其包含在项目输出中?我如何引用此库中的方法?(有一个 SerialPort.c 和一个 SerialPort.h)。这些 .mk 文件应该放在哪里?

我有一种感觉,似乎是我错过了每个人都认为理所当然的一些信息。在api示例中也没有对本地库的引用。

进展 #2:在我的代码中,我尝试使用以下方式加载库:
System.loadLibrary("libserial_port");

但是这行代码会抛出 UnsatisfiedLinkError 异常。

Native code library failed to load.java.lang.UnsatisfiedLinkError: Couldn't load libserial_port from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/myapp.apk"],nativeLibraryDirectories=[/data/app-lib/myapp.apk, /vendor/lib, /system/lib]]]: findLibrary returned null

进展#3:连接器不支持带下划线的库名称。

进展#4:连接器假定具有lib前缀。您应该在loadlibrary命令中省略它。

现在我调用System.loadLibrary(“serialport”); 并且我的库名为libserialport.so。现在我不再收到UnsatisfiedLinkError错误!

现在我们开始了解如何引用库中的方法。

1个回答

14

我所有问题的答案。适用于Android Studio 1.5.1和Gradle 2.2.1(2016年1月)。

  1. 使用Android Studio时,.so文件应该放在/app/src/main/jniLibs/[armeabi|armeabi-v7a|x86|等等]中。对于eclipse,这是一个不同的目录。

  2. 我们不需要头文件、c文件或mk文件就可以使它工作。

  3. Loadlibrary在搜索库时假定了"lib"前缀,因此如果你想加载libdoesstuff.so,那么指令应该是System.loadLibrary("doesstuff")。我还发现一些带有下划线的lib名称不受支持(虽然没有测试)。

  4. serialport api文件应该放在自己的包中(参见这个问题的答案:How to unit test serial ports in Java on Android)。将SerialPort.java和SerialPortFinder.java放在/src/java/android_serialport_api中,并将它们保留在默认包中(不要将它们移动到你的项目包中,在那里它们不起作用,不要问我为什么)。

  5. 在你的java文件中,你想使用SerialPort类,添加import android_serialport_api.*;

  6. 如果你不想编译c代码,就没有必要安装NDK(很多指南都假定这一点)。

  7. 在当前版本的gradle(2.2.1)中,不需要更改任何gradle构建文件(很多评论在SO上会告诉你这样做)。

  8. 你不能在Android Studio的项目设置中添加.so文件。将lib放在jniLibs中将把.so添加到APK中。

  9. 完整的例子(线程读取串行输入)。

    package com.yourpackage;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.io.StringWriter;import java.util.Set;
    import android_serialport_api.SerialPort;
    
    public class SerialPortReader {
        private Thread readSerialDataThread;
        private SerialPort serialPort;
        private InputStream inStream;
        private OutputStream outStream;
        private boolean shouldRun = true;
    
        public SerialPortReader() { }
    
        protected void start() {
            try {
                File portLocation = new File("/dev/ttyS1");
                serialPort = new SerialPort(portLocation, 9600, 0);
                inStream = serialPort.getInputStream();
                outStream = serialPort.getOutputStream();
                sendBytes();
            } catch (IOException e) {
                Log.e("SerialPort", "IOException while opening serial port: " + e.getMessage());
                e.printStackTrace();
            }
            startThread();
        }
    
        protected void stop() {
            // break thread
            this.shouldRun = false;
            try {
                readSerialDataThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            serialPort.close();
        }
    
        private void sendBytes() {
            // example how to send data to the opened serial port
            byte[] data = new byte[]{(byte) 0xFF, (byte) 0xAA, (byte) 0x64};
            try {
                outStream.write(data);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        private void startThread() {
            readSerialDataThread = new Thread(new Runnable() {
                public void run() {
                    while (shouldRun) {
                        int dataSize = 0;
                        try {
                            dataSize = inStream.available();
                            byte[] data = new byte[dataSize];
                            inStream.read(data);
                            processData(data);
                            Thread.sleep(50); // my serial sensor gives 20 Hz updates
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            readSerialDataThread.start();
        }
    }
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接