无法运行程序"\ndk-build.cmd":启动失败。

16

我从未接触过ndk。但是我有一个项目使用了ndk。

它给我报错:java.lang.UnsatisfiedLinkError: Native method not found:

我尝试在Google上搜索,找到了很多链接,但所有的链接都与jni.cpp文件有关,而我的错误出现在Java文件中。所以我不知道该如何纠正它。

"java.lang.UnsatisfiedLinkError: Native method not found: il.co.telavivapp2u.onceapponatime.SharedResources.ocvBitmapPreMultAlpha:(Landroi‌​‌​d/graphics/Bitmap;Landroid/graphics/Bitmap;)

我按照这个链接集成了NDK。 这个项目是由另一个开发人员完成的,我们正在添加一些其他功能。这部分由之前的开发人员完成。
我刚刚添加了Google搜索API活动和图库图像活动,它将在网格上显示图像。之前的开发人员将一些图像放在drawable文件夹中,并在画廊视图中显示它们。他在自己那边做得很好,现在也是完美运行的。但是,我所添加的相同内容却没有实现。
在应用程序可绘制的画廊视图上单击图像后,它会进入一个相机活动,该相机活动将选定的图像作为背景捕获图像。然后,我们可以对该图像进行编辑并保存。但是,在使用手机画廊和Google搜索图像时,捕获后应用程序会出现ANR。
我已设置Eclipse的NDK路径和变量,还安装了C C ++插件。
此外,控制台也显示了相关信息。
Cannot run program "\ndk-build.cmd": Launching failed .

我无法理解我犯了什么错误,请帮助我。

JNI文件

ANR发生在第207行。

这是我的代码:

package il.co.telavivapp2u.onceapponatime;

import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Environment;
import android.util.Log;
import android.view.Display;

public class SharedResources {
    public static Bitmap bmpOld = null;
    public static Bitmap bmpOldScaled = null;
    public static Bitmap bmpNew = null;
    public static Bitmap bmpNewScaled = null;

    public static int scaledX = 0, scaledY = 0;
    public static int dispX = 0, dispY = 0;
    public static int fullX = 0, fullY = 0;
    public static int picX = 0, picY = 0;

    public static String fileDir = "/OnceAppOnATime/";
    public static String fileTempDir = fileDir + "/.temp/";
    public static String fileTempNew = fileTempDir + "/temp-new.jpg";
    public static String fileTempOld = fileTempDir + "/temp-old.jpg";
    public static String fileTempMask = fileTempDir + "/temp-mask.jpg";
    public static String fileTempBlend = fileTempDir + "/temp-blend.jpg";
    public static String fileTempRetouch = fileTempDir + "/temp-retouch.jpg";
    //public static String fileLastBlend = "";

    public static BitmapFactory.Options op = new BitmapFactory.Options();

    public static Locale localeHebrew = null;

    public static int taskID = -1;

    public static boolean Init(Activity activity) { return Init(activity, false); }
    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    public static boolean Init(Activity activity, boolean force) {
        if (dispX > 0 && dispY > 0) { // Don't re-init to avoid wrong file names
            if (!force)
                return false; 
        } else {
            fileDir = Environment.getExternalStorageDirectory() + fileDir;
            fileTempDir = Environment.getExternalStorageDirectory() + fileTempDir;
            fileTempNew = Environment.getExternalStorageDirectory() + fileTempNew;
            fileTempOld = Environment.getExternalStorageDirectory() + fileTempOld;
            fileTempMask = Environment.getExternalStorageDirectory() + fileTempMask;
            fileTempBlend = Environment.getExternalStorageDirectory() + fileTempBlend;
            fileTempRetouch = Environment.getExternalStorageDirectory() + fileTempRetouch;
        }

        taskID = activity.getTaskId();

        // Find Hebrew locale, if available
        Locale availableLocales[] = Locale.getAvailableLocales();
        for (int i = 0; i < availableLocales.length; ++i) {
            String lang = availableLocales[i].getLanguage();
            if (lang.equals("he") || lang.equals("iw")) {
                localeHebrew = availableLocales[i];
                break;
            }
        }

        op.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //op.inScaled = false; // Not needed if loading bitmaps from drawable-nodpi
        op.inMutable = true;

        Display display = activity.getWindowManager().getDefaultDisplay();
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
            dispX = display.getWidth();
            dispY = display.getHeight();
        } else {
            Point dispSize = new Point();
            display.getSize(dispSize);
            dispX = dispSize.x;
            dispY = dispSize.y;
        }
        Log.w("Display Size", dispX + "x" + dispY);
        //scaledX = dispX / 2; scaledY = dispY / 2;
        scaledX = dispX; scaledY = dispY;

        return true;
    }

    public static void setLocale(Activity activity, Locale locale) {
        // This doesn't work reliably
        Locale.setDefault(locale);
        Configuration config = new Configuration();
        config.locale = locale;
        activity.getBaseContext().getResources().updateConfiguration(config,
            activity.getBaseContext().getResources().getDisplayMetrics());
    }

    public static boolean haveScaling() {
        return (dispX != scaledX || dispY != scaledY);
    }

    public static void SaveTempBitmap(Bitmap bitmap, String filename) {
        try {
            new File(fileTempDir).mkdirs();
            FileOutputStream out = new FileOutputStream(filename);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 98, out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void RecycleOldBitmaps(boolean full, boolean scaled) {
        if (full && bmpOld != null) {
            bmpOld.recycle();
            bmpOld = null;
        }
        if (scaled && bmpOldScaled != null) {
            bmpOldScaled.recycle();
            bmpOldScaled = null;
        }
    }
    public static void RecycleNewBitmaps(boolean full, boolean scaled) {
        if (full && bmpNew != null) {
            bmpNew.recycle();
            bmpNew = null;
        }
        if (scaled && bmpNewScaled != null) {
            bmpNewScaled.recycle();
            bmpNewScaled = null;
        }
    }

    //                                             0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16
    public static int sample2sample[] = new int[] {1, 1, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 16,
        16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
    public static Bitmap LoadScaledBitmap(Context ctx, int resId, float fracX, float fracY) {
        // See: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(ctx.getResources(), resId, opts);
        int imageHeight = opts.outHeight;
        int imageWidth = opts.outWidth;

        float requestX = dispX * fracX, requestY = dispY * fracY;
        opts.inSampleSize = (int)(Math.min(imageWidth / requestX, imageHeight / requestY));
        if (opts.inSampleSize < 0 || opts.inSampleSize > 32) // Sometimes index=2147483647 for some reason...
            opts.inSampleSize = 1;
        opts.inSampleSize = sample2sample[opts.inSampleSize];
        Log.w("Bitmap Decoder", "Samples: " + opts.inSampleSize);

        opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //opts.inScaled = false; // Not needed if loading bitmaps from drawable-nodpi
        opts.inMutable = true;
        opts.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(ctx.getResources(), resId, opts);
    }
    public static Bitmap LoadScaledBitmap(String filename, float fracX, float fracY) {
        // See: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filename, opts);
        int imageHeight = opts.outHeight;
        int imageWidth = opts.outWidth;

        float requestX = dispX * fracX, requestY = dispY * fracY;
        opts.inSampleSize = (int)(Math.min(imageWidth / requestX, imageHeight / requestY));
        if (opts.inSampleSize < 0 || opts.inSampleSize > 32) // Sometimes index=2147483647 for some reason...
            opts.inSampleSize = 1;
        opts.inSampleSize = sample2sample[opts.inSampleSize];
        Log.w("Bitmap Decoder", "Samples: " + opts.inSampleSize);

        opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //opts.inScaled = false; // Not needed if loading bitmaps from drawable-nodpi
        opts.inMutable = true;
        opts.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filename, opts);
    }

    public static String FileNameNow() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.ENGLISH);
        return fileDir + sdf.format(new Date()) + ".jpg";
    }

    public static native void ocvBitmapPyramidalBlend(String fNew, String fOld, String fMask, String fBlend, int levels);
    public static String ocvBitmapPyramidalBlendTimed(int levels) {
        String fBlend = fileTempBlend;//FileNameNow();

        long t = System.nanoTime();
        ocvBitmapPyramidalBlend(fileTempNew, fileTempOld, fileTempMask, fBlend, levels);
        long dt = (System.nanoTime() - t) / 1000; // Microseconds
        Log.w("OpenCV", "Blended (pyramidal) bitmaps in " + (dt / 1000.0f) + " ms");

        //fileLastBlend = fBlend;
        return fBlend;
    }

    public static native void ocvBitmapPreMultAlpha(Bitmap bitmapImg, Bitmap bitmapMask);
    public static void ocvBitmapPreMultAlphaTimed(Bitmap bitmapImg, Bitmap bitmapMask) {
        long t = System.nanoTime();
        ocvBitmapPreMultAlpha(bitmapImg, bitmapMask);
        long dt = (System.nanoTime() - t) / 1000; // Microseconds
        Log.i("Native", "Applied premultiplied alpha to bitmap in " + (dt / 1000.0f) + " ms");
    }

    public static native void ocvBitmapContrastSaturationSet(Bitmap bitmapImg);
    public static void ocvBitmapContrastSaturationSetTimed(Bitmap bitmapImg) {
        long t = System.nanoTime();
        ocvBitmapContrastSaturationSet(bitmapImg);
        long dt = (System.nanoTime() - t) / 1000; // Microseconds
        Log.i("Native", "Assigned contrast/saturation bitmap in " + (dt / 1000.0f) + " ms");
    }

    public static native void ocvBitmapContrastSaturationSrc(Bitmap bitmapImg, Bitmap bitmapSrc, float contrast, float saturation);
    public static void ocvBitmapContrastSaturationSrcTimed(Bitmap bitmapImg, Bitmap bitmapSrc, float contrast, float saturation) {
        long t = System.nanoTime();
        ocvBitmapContrastSaturationSrc(bitmapImg, bitmapSrc, contrast, saturation);
        long dt = (System.nanoTime() - t) / 1000; // Microseconds
        Log.i("Native", "Applied contrast/saturation (from src) to bitmap in " + (dt / 1000.0f) + " ms");
    }

    public static native void ocvBitmapContrastSaturation(Bitmap bitmapImg, float contrast, float saturation);
    public static void ocvBitmapContrastSaturationTimed(Bitmap bitmapImg, float contrast, float saturation) {
        long t = System.nanoTime();
        ocvBitmapContrastSaturation(bitmapImg, contrast, saturation);
        long dt = (System.nanoTime() - t) / 1000; // Microseconds
        Log.i("Native", "Applied contrast/saturation to bitmap in " + (dt / 1000.0f) + " ms");
    }

}

另外 右键单击项目 - >Android 工具 -> 添加本地支持


Add Native Support is missing. I have Android Native Development Tools installed. Then also it's missing.

3
看起来你的 IDE 中 ndk-build 的路径配置有误。接下来,使用 zip 文件工具验证一个或多个 .so 文件是否会出现在 .apk 中。最后,你是否在 Java 中显式地加载了该库? - Chris Stratton
由于这个项目是由另一个开发者完成的,所以我不确定你在谈论哪个库。但是,在项目的libs文件夹中有两个文件夹,一个是“armeabi”,另一个是“armeabi-v7a”。每个文件夹都包含两个.so文件。一个是“libOAOAT.so”,另一个是“libopencv_java.so”。此外,还有一个库被使用,“OpenCV Library - 2.4.3”也在同一工作区中。@ChrisStratton - TheLittleNaruto
您发布了一个错误消息,建议 nkd-build 不在尝试运行的稍微不同的路径上(否则可能存在某些权限问题)。另外,请检查 .so 文件是否被包含在 .apk 文件中,它在项目文件夹中是一个开端,但并非关键测试。最后,您最终需要验证 .so 文件本身的函数名称 - 您的棘手命名宏可能有效也可能无效 - 我会使用 ndk objdump 进行验证,但我可能不会在第一次使用该宏时烦恼。 - Chris Stratton
请查看ndk安装示例目录中的hello-jni示例。 - Chris Stratton
好的,让我检查一下,替换宏是否真正起作用了。@ChrisStratton - TheLittleNaruto
显示剩余7条评论
3个回答

1
UnsatisfiedLinkError是由于Java类和C类之间的桥梁断裂引起的; Java中的方法名称应与C / C ++类中的方法名称匹配。 在编译时,在Java和C / C ++之间创建桥梁,因此如果方法名称不正确,则不会响应。 以下是示例 Java中的方法名称如下
public native String Stub(){}

在JNI中应该与您的应用程序包名称+类名+方法名相同,如下所示

JNIEXPORT jstring JNICALL Java_com_packageName_ClassName_MethodName

我已经添加了JNI文件和SharedResources。函数名称相同。在SharedResources中,它是public static native void ocvBitmapPreMultAlpha(Bitmap bitmapImg, Bitmap bitmapMask);而在JNI文件中也是相同的。 - TheLittleNaruto

0
  • 在新的系统变量中添加正确的NDK路径:例如:"ANDROID_NDK=..."
  • 在项目的属性中,在 "C/C++ Build" 中,在 "Build command:" 中,像这样输入变量:${ANDROID_NDK}/ndk-build.cmd

-1
关键错误是“无法运行程序“ndk-build”:启动失败”。 如果无法运行,则不会构建.so,这会导致UnsatisfiedLinkError。 首先解决ndk-build问题。
尝试从“\ ndk-build.cmd”中删除初始的'\'。 当我运行“ndk-build.cmd”时,它可以正常工作。

这个问题在评论中已经被广泛讨论过了。发帖人声称.apk文件中存在.so文件,尽管可能并不是绝对的(在当前版本中),等等。基本上,这个问题看起来像是去年秋天就被放弃了。 - Chris Stratton
我看到的只是人们提到可能需要更改Java代码和建议修复NDK路径。但这两者都没有帮助到我。删除斜杠起了作用,而其他人并没有提出这个建议。 - DrChandra
该问题是在五个月前发布的第一条评论中提出的。 - Chris Stratton
你没有明确建议他删除前导斜杠。你的评论只涉及路径。接下来,他开始讨论“D:\ NDK \ android-ndk-r9”,这表明他并没有理解为他应该删除斜杠。你的评论促使我检查我的路径,我发现它是正确的。我尝试的下一件事是删除前导斜杠。那样就解决了。你为什么要如此努力地否定我说的话?它起作用了。 - DrChandra
我特别告诉了他们,看起来他们试图从错误的路径运行它。既然他们接着说有.so文件正在被构建,似乎这不是问题的主要问题,并且在某个时候已经被偶然地克服了。 - Chris Stratton

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