【问题标题】:Cannot run program "\ndk-build.cmd": Launching failed无法运行程序“\ndk-build.cmd”:启动失败
【发布时间】:2013-10-11 09:15:59
【问题描述】:

我从未在 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;)

我在this link 之后集成了NDK。 这个项目是由另一个开发者完成的 我们正在其中添加更多功能。 这部分是以前的开发者完成的。

我刚刚添加了 Google Search API Activity 和 Gallery image Activity,它将在网格上显示图像。以前的开发人员已将一些图像放在可绘制文件夹中并将其显示到图库视图中。无论他最后做了什么,它都在完美运行。即使现在也。但是我添加的内容并没有发生同样的事情

在应用程序可绘制图库视图上单击图像后,它将转到相机活动,该活动将捕获以所选图像作为背景的图像。然后我们可以编辑并保存该图像。但是如果在捕获应用程序后移动图库和谷歌搜索图像会出现 ANR。

我已将 NDK 路径和变量设置为 eclipse,还安装了 c c++ 插件

控制台也在显示

Cannot run program "\ndk-build.cmd": Launching failed .

我无法理解我在哪里犯了错误。请帮帮我。

JNI FILE

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");
    }

}

还有right click on project - &gt;Android Tools -&gt; Add Native Support

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

【问题讨论】:

  • 您的 ide 中配置的 ndk-build 路径似乎错误。接下来使用 zip 文件工具验证一个或多个 .so 文件是否以 .apk 结尾。最后,您是否从 Java 显式加载库?
  • "D:\NDK\android-ndk-r9" 这是我的 NDk 路径,我在 ide 中设置了它。 @ChrisStratton
  • 由于这个项目是由另一个开发人员完成的,所以我不确定你在说什么库。但是是的,项目的 libs 文件夹中有两个文件夹,一个是“armeabi”,另一个是“armeabi-v7a”。每个文件夹都包含两个 .so 文件。一个是“libOAOAT.so”,另一个是“libopencv_java.so”。还有一个使用“OpenCV Library - 2.4.3”的库在同一个工作区中。 @ChrisStratton
  • 您发布了一条错误消息,表明 nkd-build 不在尝试运行它的路径略有不同(否则存在一些权限问题)另外请检查 .so文件正在进入 .apk 文件 - 它在项目文件夹中是一个开始,但不是关键测试。最后,您最终需要从 .so 文件本身验证函数名称 - 您棘手的命名宏可能工作也可能不工作 - 我会为此使用 ndk objdump,但我可能不会打扰首先是宏。
  • 我检查了 apk 文件,它包含 .so 文件。我想知道如何用您的建议替换宏。你能给我一些链接吗? @ChrisStratton

标签: java android c++ eclipse android-ndk


【解决方案1】:

UnsatisfiedLinked 错误是由于 java 类和 c 类之间的桥坏了; java 中方法的名称应与 C/c++ 类中的方法匹配。 在 Java 和 c/c++ 之间创建编译桥时,如果方法名称不正确,它不会响应。 示例如下 方法名 injava 如下

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 文件中是一样的
【解决方案2】:
  • 在新的变量系统中添加正确的 NDK 路径:例如。 : "ANDROID_NDK=..."
  • 在您项目的属性中,在“C/C++ Build”中,在“Build command:”中,输入如下变量:${ANDROID_NDK}/ndk-build.cmd

【讨论】:

    【解决方案3】:

    关键错误是“无法运行程序“ndk-build”:启动失败”。如果没有运行,.so 不会被构建,这会导致 UnsatisfiedLinkError。先解决ndk-build问题。

    尝试从“\ndk-build.cmd”中删除初始的“\”。当我运行“ndk-build.cmd”时,它可以工作。

    【讨论】:

    • 这已经在 cmets 中得到了广泛的介绍。发帖人声称 .so 文件存在于 apk 中——尽管可能不是绝对如此(在当前版本中)等等。基本上这个问题给出了去年秋天被放弃的所有外观。
    • 我看到的只是人们提到他们认为可能需要的 Java 代码更改,以及修复 NDK 路径的建议。这些都没有帮助我。删除斜线有效,没有其他人建议这样做。
    • 五个月前发布的第一条评论中提出了该问题。
    • 您没有特别建议他删除前导斜杠。您的评论仅涉及路径。他接下来开始讨论“D:\NDK\android-ndk-r9”,这表明他并不认为这意味着他应该删除斜线。您的评论促使我检查我的路径,我发现它是正确的。我尝试的下一件事是删除前导斜杠。那解决了它。你为什么要如此努力地否定我所说的?它奏效了。
    • 我特别告诉他们,他们似乎试图从错误的路径运行它。由于他们接着说正在构建 .so 文件,因此这似乎不是问题中的主要问题,并且在某个时候偶然得到了解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 2020-09-26
    • 2010-12-29
    相关资源
    最近更新 更多