Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating .so files in Android Studio 1.0.2 with NDK

I have been working on getting a very simple NDKSample application built as per the walk-through here. My problem is, I cannot get Android Studio to generate the .so files, so I have no libraries.

I understand that NDK Support is deprecated now and there will be an alternative provided early this year, however there doesn't appear to be anything actively stopping me from using this feature currently. When I build my project, I am given the following Warning (Not an error):

WARNING [Project: :app] Current NDK support is deprecated. Alternative will be provided in the future.

My project builds, but when I run the .apk it crashes (as expected) as it cant find the libraries/.so files. We would expect these to be generated when the project is built, as per the example, is this correct? Here is the error:

java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndksample-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]] couldn't find "libMyLib.so"

About my environment

Windows 7, Android Studio 1.0.2, ADB is running Nexus 5 (emulator-5554)

My code

As per the example:

Main Activity.java

package com.example.ndksample;

//import android.support.v7.app.ActionBarActivity;
// This line is not needed as we are not targetting older devices
import android.app.Activity; //Import this app package to use onCreate etc.
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;


public class MainActivity extends Activity {

    static{
        System.loadLibrary("MyLib");
    }

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

        TextView tv = (TextView) findViewById(R.id.my_textview);
        tv.setText(getStringFromNative());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public native String getStringFromNative();
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView
        android:id="@+id/my_textview"
        android:text="@string/hello_world" android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

main.c

#include "com_example_ndksample_MainActivity.h"
/* Header for class com_example_ndksample_MainActivity */

JNIEXPORT jstring JNICALL Java_com_example_ndksample_app_MainActivity_getStringFromNative
    (JNIEnv * env, jobject obj)
    {
        return (*env)->NewStringUTF(env, "Hello from Kyle");
    }

build.gradle note: app

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.example.ndksample"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"

        ndk {
            moduleName "MyLib"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
}

local.properties

## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=D\:\\Programs\\Android\\Android SDK
ndk.dir=D\:\\Programs\\Android\\Android NDK

My questions if anyone is able to help please:

Ultimately, how do I generate the required .so files!!??

Sub questions that may help in answering the main question:

My directory layout had my jni dir under app (so NDKSample/app/jni), is this correct? I was advised here not to place the c files in the standard jni directory. I trialed this, and upon building the project, it crashed. Error:

*FAILURE: Build failed with an exception.

  • What went wrong: Execution failed for task ':app:compileDebugNdk'.

    com.android.ide.common.internal.LoggedErrorException: Failed to run command: D:\Programs\Android\Android NDK\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=C:\Users\Kyle\AndroidStudioProjects\NDKSample\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-21 NDK_OUT=C:\Users\Kyle\AndroidStudioProjects\NDKSample\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=C:\Users\Kyle\AndroidStudioProjects\NDKSample\app\build\intermediates\ndk\debug\lib APP_ABI=all Error Code: 1*

The example from Intel above does not direct me to build an Android.mk file, the example does not and he generates a working application. I have trialed putting one in the jni directory, however it did not help. Should I be creating one, and if so, where should I put it

Is the below image of my directories correct? Directories

Any help would be greatly appreciated.

Kyle

like image 598
KyleM Avatar asked Jan 05 '15 06:01

KyleM


1 Answers

the current NDK support in Android Studio is minimal, hence they deprecated it with 1.0.

When using it, an Android.mk file is automatically generated and your sources compiled when you build your project. Right now it seems the compilation is failing, but you should be able to get the initial error message from the Gradle Console.

If you don't get any other error messages, I suspect that the call to ndk-build is failing because there is a space inside your NDK's installation path (Android NDK)

You can either fix the current error and continue with your current setup, or disable the default NDK integration, create Android.mk/Application.mk files and call ndk-build(.cmd) yourself or from a task:

import org.apache.tools.ant.taskdefs.condition.Os

android {
    sourceSets.main {
        jniLibs.srcDir 'src/main/libs' //set .so files location to libs
        jni.srcDirs = [] //disable automatic ndk-build call
    }

    // call regular ndk-build(.cmd) script from app directory
    task ndkBuild(type: Exec) {
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
        } else {
            commandLine 'ndk-build', '-C', file('src/main').absolutePath
        }
    }
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
}
like image 123
ph0b Avatar answered Sep 30 '22 18:09

ph0b