【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法

错误描述

今天使用第三方的so库时候,调用JNI方法时出现了错误。报错如下所示:

11-01 16:39:20.979 4669-4669/com.netease.xtc.cloudmusic E/art: No implementation found for void com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(android.content.Context) (tried Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit and Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit__Landroid_content_Context_2)
11-01 16:39:20.980 4669-4669/com.netease.xtc.cloudmusic D/AndroidRuntime: Shutting down VM
11-01 16:39:20.984 4669-4669/com.netease.xtc.cloudmusic E/AndroidRuntime: FATAL EXCEPTION: main
                                                                          Process: com.netease.xtc.cloudmusic, PID: 4669
                                                                          java.lang.UnsatisfiedLinkError: No implementation found for void com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(android.content.Context) (tried Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit and Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit__Landroid_content_Context_2)
                                                                              at com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(Native Method)
                                                                              at com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.<clinit>(NeteaseMusicUtils.java:11)
                                                                              at com.netease.xtc.cloudmusic.MainActivity$1.onClick(MainActivity.java:26)
                                                                              at android.view.View.performClick(View.java:5277)
                                                                              at android.view.View$PerformClick.run(View.java:21704)
                                                                              at android.os.Handler.handleCallback(Handler.java:815)
                                                                              at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                              at android.os.Looper.loop(Looper.java:207)
                                                                              at android.app.ActivityThread.main(ActivityThread.java:5905)
                                                                              at java.lang.reflect.Method.invoke(Native Method)
                                                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
                                                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)

在MainActivity中,尝试调用NeteaseMusicUtils类封装好的JNI方法,代码如下所示:

package com.netease.xtc.cloudmusic;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

import com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String params = NeteaseMusicUtils.getUrlParameters("/search","{\"keyword\":\"周杰伦\",\"limit\":10,\"offset\":0}");

                Snackbar.make(view, "params = " + params , Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

}

而com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils代码如下:

package com.netease.xtc.cloudmusic.utils;

import android.content.Context;

import com.netease.xtc.cloudmusic.app.NeteaseMusicApplication;

public class NeteaseMusicUtils {
    static {
        //加载库文件
        System.loadLibrary("poison");
        nativeInit(NeteaseMusicApplication.getContext());
    }

    /**
     * 初始化,必须
     * @param context
     */
    public native static void nativeInit(Context context);

    /**
     * 获取请求中"params"的值
     * 例:如果调用搜索接口,搜索keyword=周杰伦 limit=10 offset=0
     * params=getUrlParameters("/search","{\"keyword\":\"周杰伦\",\"limit\":10,\"offset\":0}\")
     * @param requestUri 接口说明中的uri
     * @param paramJson 接口说明中的参数json表达,如果为空请传"{}"
     * @return
     */
    public native static String getUrlParameters(String requestUri, String paramJson);
}

其中so库位置如下所示:

错误分析

再一次查看下错误日志,如下所示:

11-01 16:47:53.363 11117-11117/com.netease.xtc.cloudmusic E/art: No implementation found for void com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(android.content.Context) (tried Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit and Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit__Landroid_content_Context_2)
11-01 16:47:53.364 11117-11117/com.netease.xtc.cloudmusic D/AndroidRuntime: Shutting down VM
11-01 16:47:53.365 11117-11131/com.netease.xtc.cloudmusic I/[MALI][Gralloc]: [+]r_hnd(0xf24b3960), client(36), share_fd(44)
11-01 16:47:53.373 11117-11117/com.netease.xtc.cloudmusic E/AndroidRuntime: FATAL EXCEPTION: main
                                                                            Process: com.netease.xtc.cloudmusic, PID: 11117
                                                                            java.lang.UnsatisfiedLinkError: No implementation found for void com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(android.content.Context) (tried Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit and Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit__Landroid_content_Context_2)
                                                                                at com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(Native Method)
                                                                                at com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.<clinit>(NeteaseMusicUtils.java:11)
                                                                                at com.netease.xtc.cloudmusic.MainActivity$1.onClick(MainActivity.java:26)
                                                                                at android.view.View.performClick(View.java:5277)
                                                                                at android.view.View$PerformClick.run(View.java:21704)
                                                                                at android.os.Handler.handleCallback(Handler.java:815)
                                                                                at android.os.Handler.dispatchMessage(Handler.java:104)
                                                                                at android.os.Looper.loop(Looper.java:207)
                                                                                at android.app.ActivityThread.main(ActivityThread.java:5905)
                                                                                at java.lang.reflect.Method.invoke(Native Method)
                                                                                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
                                                                                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:749)

错误日志提示我们没有 Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit 方法的实现,如下所示:

 java.lang.UnsatisfiedLinkError: No implementation found for void com.netease.xtc.cloudmusic.utils.NeteaseMusicUtils.nativeInit(android.content.Context) (tried Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit and Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit__Landroid_content_Context_2)

然后我去咨询了一下第三方提供so库的工作人员,回复说NeteaseMusicUtils类的包名一定要是com.netease.cloudmusic.utils。原因是JNI接口Java_com_netease_xtc_cloudmusic_utils_NeteaseMusicUtils_nativeInit中,com.netease.xtc.cloudmusic.utils代表的是package nameNeteaseMusicUtils则是class name
而第三方提供so库的工作人员的c文件的定义JNI接口为Java_com_netease_cloudmusic_utils_NeteaseMusicUtils_nativeInit,即:package name必须为:com.netease.cloudmusic.utils,而class name必须为 NeteaseMusicUtils
也就是说,我们.so中函数声明涉及到的package name和class name与调用它的package name和class name不符。因此我们要改变我们工程中的package name和class name。使其与.so文件中函数签名提示的一致,在这个类中加入native方法的声明。

错误解决方法

好吧,我新建一个包名为com.netease.cloudmusic.utils,并把NeteaseMusicUtils类移到该包名地下。

未移动NeteaseMusicUtils到com.netease.cloudmusic.utils包之前

移动NeteaseMusicUtils到com.netease.cloudmusic.utils包之后

然后重新编译,成功运行。

JNI的命名规则

这里顺便说一下JNI的命名规则,对于传统的JNI编程来说,JNI方法跟Java类方法的名称之间有一定的对应关系,要遵循一定的命名规则,如下所示:

  1. 前缀: Java_
  2. 类的全限定名,用下划线进行分隔(_):com_oyp_jni_JniTest
  3. 方法名:getTestString
  4. JNI函数指定第一个参数: JNIEnv *
  5. JNI函数指定第二个参数: jobject
  6. 实际Java参数: jstring, jint ….

所以对于在Java类 com.oyp.jni.JniTest类的一个方法:

public native String getTestString (String oyp);

其对应的jni层的方法如下:

jstring Java_com_oyp_jni_JniTest_getTestString(JNIEnv * e, jobject clazz, jstring oyp);

如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。
注意,我们也可以利用函数注册的方法,将Java层的方法名跟JNI层的方法名的对应关系保存起来,注册到DVM中,就不需要这样的命名规范了。

JNI 数据类型

我们知道Java的数据类型是跟C/C++的数据类型是不一样的,而JNI是处于Java和Native本地库(大部分是用C/C++写的)中间的一层,JNI对于两种不同的数据类型之间必须做一种转换,所以在JNI跟Java之间就会有数据类型的对应关系。 在JNI中,提供了以下各种数据类型,可以分为原生类型和引用类型: 对于原生类型有:jchar, jbyte, jshort, jint, jlong, jfloat, jdouble, jboolean,其与java端的数据类型对应如下表:

java jni
char jchar
byte jbyte
short jshort
int jint
long jlong
float jfloat
double jdouble
boolean jboolean

对于引用类型则有:jobject, jstring, jthrowable, jclass, jarray, 以及继承于jarray,对应于其原生类型的8种jarray和jobjectarray。


作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/ouyang_peng/article/details/52973274

时间: 2024-09-12 16:07:16

【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法的相关文章

android 64位系统 so文件出错 java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad in

问题描述 04-11 19:26:14.805: E/SMACK-Voe(14608): enter JNI_OnLoad04-11 19:26:14.805: E/SMACK-Voe(14608): TORNADO007 WEBRTC_EASEMOB not DEFINED04-11 19:26:14.805: E/art(14608): ----- class 'Lcom/hyphenate/media/AVNative;' cl=0x12c92cc0 -----04-11 19:26:14

我的Android进阶之旅------&amp;gt;关于调用Webservice查询火车票时刻表的几个接口介绍

今天发现一个可以提供火车票时刻表查询的WebService,先记录下来以后如果写一个火车票时刻表查询的Android App的话就用的着.首先该WebService的的名字是TrainTimeWebService,地址是:http://webservice.webxml.com.cn/WebServices/TrainTimeWebService.asmx. 当然关于WebService的相关知识可以查看本人的另外文章: 我的Android进阶之旅------>Android通过调用Webser

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)

正如在<我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)>一文中看到的,在AbstractBoard的代码中,当程序需要创建N个Piece对象时,程序会直接调用ImageUtil的getPlayImages()方法去获取图片,该方法会随机从res/drawable目录中取得N张图片. 下面是res/drawable目录视图: 为了让getPlayImages()方法能随机从res/drawable目录中取得N张图片,具体实现分为以下几步: 通

我的Android进阶之旅------&amp;gt; Android为TextView组件中显示的文本添加背景色

通过上一篇文章 我的Android进阶之旅------> Android在TextView中显示图片方法 (地址:http://blog.csdn.net/ouyang_peng/article/details/46916963)      我们学会了在TextView中显示图片的方法,现在我们来学习如何为TextView组件中显示的文本添加背景色.要求完成的样子如图所示: 首先来学习使用BackgroundColorSpan对象设置文字背景色,代码如下: TextView textView=(

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之实现游戏逻辑(五)

在上一篇<我的Android进阶之旅------>Android疯狂连连看游戏的实现之加载界面图片和实现游戏Activity(四)>中提到的两个类: GameConf:负责管理游戏的初始化设置信息. GameService:负责游戏的逻辑实现. 其中GameConf的代码如下:cn\oyp\link\utils\GameConf.java package cn.oyp.link.utils; import android.content.Context; /** * 保存游戏配置的对象

我的Android进阶之旅------&amp;gt;Android中AsyncTask源码分析

在我的<我的Android进阶之旅------>android异步加载图片显示,并且对图片进行缓存实例>文章中,先后使用了Handler和AsyncTask两种方式实现异步任务机制. 下面先来看一段代码,这段代码是用来显示条目时候调用的方法. @Override public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView = null; TextView textV

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之状态数据模型(三)

对于游戏玩家而言,游戏界面上看到的"元素"千变万化:但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已.因此建立游戏的状态数据模型是实现游戏逻辑的重要步骤. 1.定义数据模型 连连看的界面是一个NxM的"网格",每个网格上显示一张图片.而这个网格只需要一个二维数组来定义即可,而每个网格上所显示的图片,对于底层数据模型来说,不同的图片对于着不同的数值即可. 对于上图所示的数据模型,只要让数值为0的网格上不绘制图片,其他数值的网

我的Android进阶之旅------&amp;gt;介绍一款集录制与剪辑为一体的屏幕GIF 动画制作工具 GifCam

由于上一篇文章:我的Android进阶之旅------>Android之动画之Frame Animation实例 中展示的是Frame动画效果,但是之前我是将图片截取下来,不好说明确切的动画过程,因此今天百度了一下gif动画的制作工具,找到了这款不错的软件GifCam.然后我使用该软件将动画制作成gif动画,然后更新了上一篇文章上传了新制作的gif动画,使博客的说明效果更佳. 该软件的界面如下所示: 该软件的操作步骤如下: 1.拖动 GifCam 标题栏,改变其位置,并调整 GifCam 窗口大

我的Android进阶之旅------&amp;gt;Android疯狂连连看游戏的实现之开发游戏界面(二)

连连看的游戏界面十分简单,大致可以分为两个区域: 游戏主界面区 控制按钮和数据显示区 1.开发界面布局 本程序使用一个RelativeLayout作为整体的界面布局元素,界面布局上面是一个自定义组件,下面是一个水平排列的LinearLayout. 下面是本程序的布局文件:/res/layout/main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=