Android Studio, Gradle und NDK


153

Ich bin sehr neu in diesem ganzen Gradle und Android Studio Support. Ich habe es geschafft, mein Android-Projekt mithilfe der Exportoption in Gradle zu konvertieren.

Ich suche jedoch nach einer Dokumentation oder einem Ausgangspunkt für die Integration des NDK-Builds in den Gradle-Build-Prozess.

Wenn möglich, benötige ich auch eine Art "After" -Stufe, in der die Build-Binärdateien (.so-Dateien) in das Asset-Verzeichnis kopiert werden.


Ich habe meine Antwort in dem unten genannten Link stackoverflow.com/questions/20900814/…
Ahmad Ali Nasir

24
Neue Leser: Beachten Sie, dass diese Frage ursprünglich während der Beta-Phase von Android Studio gestellt wurde. Die Antwort hat sich im Laufe der Zeit geändert. Achten Sie auf die in den Antworten erwähnte Gradle-Version sowie darauf, wann die Antworten tatsächlich veröffentlicht wurden.
Sean Beach

Wenn sich etwas wirklich ändert, werde ich die Frage bearbeiten, um den Status zu überprüfen
plaisthos

Android Studio 1.3 auf Canary Channel unterstützt NDK vollständig. Referenz: tools.android.com/download/studio/canary/latest
Vikasdeep Singh

18. Juni 2015: Android Studio 1.3 Beta ist jetzt im Beta-Kanal verfügbar! Leider enthält dieser Build noch keine C / C ++ - Unterstützung. Quelle: tools.android.com/recent/androidstudio13betaavailable
fastr.de

Antworten:


85

Wir haben eine erste Version der Integration als Vorschau in 1.3 veröffentlicht: http://tools.android.com/tech-docs/android-ndk-preview

Die Integration bleibt eine Vorschau, auch wenn 1.3 endgültig ist. Keine aktuelle ETA, wann es endgültig sein wird (Stand 10.07.2015).

Weitere Informationen finden Sie hier: http://tools.android.com/tech-docs/android-ndk-preview


2
Wäre toll, wenn ich NDK und Befehlsvervollständigung mit Debugging unter Android Studio (und Gradle-Unterstützung) verwenden könnte
Pulver366

1
@GREnvoy - Wie konfigurieren wir den richtigen NDK-Builder in Android Studio? Können Sie mir bitte die Schritte geben? :)
Shravan

7
@DirtyBeach Warum ist es veraltet? Es gibt noch keine Integration des NDK in Studio. Wir arbeiten daran, aber derzeit keine ETA.
Xavier Ducrohet

2
Meine Aktion basierte darauf, wie ich "Integration" definierte. Ich verstand es als "eine Möglichkeit, das NDK mit Gradle zu verwenden", die es jetzt gibt, obwohl keine von ihnen fantastische Lösungen sind. Basierend auf Ihrem Kommentar scheint Ihr Team jedoch etwas anderes im Sinn zu haben, was eine echte Integration sein könnte. Ich ziehe meine vorherige Aussage zurück.
Sean Beach

2
Die NDK-Integration wurde während Google IO 2015 angekündigt. Sie ist in Android Studio 1.3 verfügbar (die Vorschau kann bald heruntergeladen werden. Ich werde einen Link veröffentlichen, sobald sie verfügbar ist).
Zypresse Frankenfeld

43

UPDATE: Das Android Studio mit NDK-Unterstützung ist ab sofort erhältlich: http://tools.android.com/tech-docs/android-ndk-preview

Zum Erstellen mit einem Skript sollte die folgende Gradle-Lösung funktionieren:

Ich verwende mein Build-Skript und füge es meiner Datei hinzu (scheint zu funktionieren 0.8+): Dies scheint der folgenden Lösung zu entsprechen (sieht aber in der Gradle-Datei besser aus):

 android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['native-libs']
            jni.srcDirs = [] //disable automatic ndk-build
        }
    }
 }

Der Build schlägt leider nicht fehl, wenn das Verzeichnis nicht vorhanden ist oder keine .soDateien enthält .


5
Dies funktioniert nicht mehr mit der neuen Android Studio-Version, Problemumgehung?
Pulver366

@ Pulver366 Siehe meine Antwort.
Leandros

2
Ein bisschen groovige Magie : tasks.withType(com.android.build.gradle.tasks.PackageApplication) { it.jniFolders = [file("libs")] as Set }. Vielen Dank für die Hilfe!
trnl

Was ist das Verfahren für Android Studio 0.8.9
Pandiri Deepak

1
@plaisthos Vielen Dank für den Hinweis auf die richtige Richtung! Die zweite Zeile im Gradle-Skript jni.srcDirs = [] //disable automatic ndk-buildist sehr wichtig, da sie verhindert, dass Android Studio den C / C ++ - Quellcode neu erstellt. Ich habe zwei Tage lang versucht, dies herauszufinden, bis ich Ihren Beitrag sah und dies mein Problem löste. Ich denke wirklich, dass der NDK-Build besser separat nur von Android.mk-Befehlszeilen-Makefile erstellt wird, nicht von Gradle-Skripten, da C / C ++ seit mehr als 40 Jahren von Makefile erstellt wird!
Tonga

40

Mit dem Update von Android Studio auf 1.0 wurde die Unterstützung der NDK-Toolchain immens verbessert ( Hinweis: Bitte lesen Sie meine Updates am Ende dieses Beitrags, um die Verwendung mit dem neuen experimentellen Gradle-Plugin und Android Studio 1.5 zu sehen ).

Android Studio und das NDK sind gut genug integriert, sodass Sie nur einen ndk {} -Block im build.gradle Ihres Moduls erstellen und Ihre Quelldateien in das Verzeichnis (module) / src / main / jni legen müssen - und schon sind Sie da getan!

Kein ndk-Build mehr über die Kommandozeile.

Ich habe alles darüber in meinem Blog-Beitrag hier geschrieben: http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/

Die wichtigsten Punkte sind:

Hier müssen Sie zwei Dinge wissen. Wenn Sie externe Bibliotheken haben, die in die Android-Anwendung geladen werden sollen, werden diese standardmäßig in der Datei (module) / src / main / jniLibs gesucht. Sie können dies ändern, indem Sie sourceSets.main.jniLibs.srcDirs im build.gradle Ihres Moduls festlegen. Sie benötigen ein Unterverzeichnis mit Bibliotheken für jede Architektur, auf die Sie abzielen (z. B. x86, arm, mips, arm64-v8a usw.).

Der Code, den Sie standardmäßig von der NDK-Toolchain kompilieren möchten, befindet sich in (module) / src / main / jni. Ähnlich wie oben können Sie ihn ändern, indem Sie sourceSets.main.jni.srcDirs im build.gradle Ihres Moduls festlegen

und fügen Sie dies in das build.gradle Ihres Moduls ein:

ndk {
  moduleName "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
  cFlags "-std=c++11 -fexceptions" // Add provisions to allow C++11 functionality
  stl "gnustl_shared" // Which STL library to use: gnustl or stlport
}

Das ist der Prozess des Kompilierens Ihres C ++ - Codes. Von dort aus müssen Sie ihn laden und Wrapper erstellen. Nach Ihrer Frage zu urteilen, wissen Sie jedoch bereits, wie das alles funktioniert, damit ich nicht erneut hashe.

Außerdem habe ich hier ein Github-Repo dieses Beispiels platziert: http://github.com/sureshjoshi/android-ndk-swig-example

UPDATE: 14. Juni 2015

Wenn Android Studio 1.3 herauskommt, sollte C ++ über das JetBrains CLion-Plugin besser unterstützt werden. Ich gehe derzeit davon aus, dass dies die Entwicklung von Java und C ++ in Android Studio ermöglicht. Ich denke jedoch, dass wir weiterhin den Gradle NDK-Abschnitt verwenden müssen, wie ich oben angegeben habe. Ich denke außerdem, dass Java <-> C ++ - Wrapper-Dateien weiterhin geschrieben werden müssen, es sei denn, CLion führt diese automatisch aus.

UPDATE: 5. Januar 2016

Ich habe mein Blog und mein Github-Repo (im Entwicklungszweig) aktualisiert, um Android Studio 1.5 mit dem neuesten experimentellen Gradle-Plugin (0.6.0-alpha3) zu verwenden.

http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/ http://github.com/sureshjoshi/android-ndk-swig-example

Der Gradle-Build für den NDK-Abschnitt sieht nun folgendermaßen aus:

android.ndk {
    moduleName = "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
    cppFlags.add("-std=c++11") // Add provisions to allow C++11 functionality
    cppFlags.add("-fexceptions")
    stl = "gnustl_shared" // Which STL library to use: gnustl or stlport
}

Außerdem hat Android Studio eine automatische Vervollständigung für C ++ - Java-generierte Wrapper mit dem Schlüsselwort 'native':

Beispiel für die automatische Vervollständigung von C ++ - Java-Wrapper

Es ist jedoch nicht ganz rosig ... Wenn Sie SWIG verwenden, um eine Bibliothek zum automatischen Generieren von Code zu verpacken, und dann versuchen, das native Schlüsselwort zur automatischen Generierung zu verwenden, wird der Code an der falschen Stelle in Ihrem Swig _wrap abgelegt .cxx-Datei ... Sie müssen sie also in den Block "extern C" verschieben:

C ++ - Java-Wrapper wurde an den richtigen Speicherort verschoben

UPDATE: 15. Oktober 2017

Ich würde mich sehr freuen, wenn ich nicht erwähnen würde, dass Android Studio 2.2 ab im Wesentlichen "native" (kein Wortspiel) Unterstützung für die NDK-Toolchain über Gradle und CMake bietet. Wenn Sie jetzt ein neues Projekt erstellen, wählen Sie einfach C ++ - Unterstützung und los geht's.

Sie müssen immer noch Ihren eigenen JNI-Layer-Code generieren oder die oben erwähnte SWIG-Technik verwenden, aber das Gerüst eines C ++ in Android-Projekts ist jetzt trivial.

Änderungen in der CMakeLists-Datei (in der Sie Ihre C ++ - Quelldateien ablegen) werden von Android Studio übernommen und alle zugehörigen Bibliotheken automatisch neu kompiliert.


1
Setzen Sie die * .so in (Modul) / src / main / jniLibs
fawkes

Warum ist NDEBUG immer eingestellt, wenn Android Studio verwendet wird, auch bei Debug-Builds
pt123

35

In Google IO 2015 kündigte Google die vollständige NDK-Integration in Android Studio 1.3 an.

Es ist jetzt nicht mehr in der Vorschau und für alle verfügbar: https://developer.android.com/studio/projects/add-native-code.html

Alte Antwort: Gradle ruft automatisch an, ndk-buildwenn Sie ein jniVerzeichnis in Ihren Projektquellen haben.

Dies funktioniert unter Android Studio 0.5.9 (Canary Build).

  1. Laden Sie das NDK herunter

  2. Fügen Sie entweder ANDROID_NDK_HOMEzu Ihren Umgebungsvariablen oder ndk.dir=/path/to/ndkzu Ihren local.propertiesin Ihrem Android Studio-Projekt hinzu. Dadurch kann Android Studio das ndk automatisch ausführen.

  3. Laden Sie die neuesten Gradle-Beispielprojekte herunter , um ein Beispiel für ein ndk-Projekt zu sehen. (Sie sind am Ende der Seite). Ein gutes Beispielprojekt ist ndkJniLib.

  4. Kopieren Sie die gradle.buildaus den NDK-Beispielprojekten. Es wird ungefähr so ​​aussehen. Dies gradle.builderstellt eine andere apk für jede Architektur. Sie müssen im Bereich auswählen, welche Architektur Sie möchten build variants. Bereich Varianten erstellen

    apply plugin: 'android'
    
    dependencies {
        compile project(':lib')
    }
    
    android {
        compileSdkVersion 19
        buildToolsVersion "19.0.2"
    
        // This actual the app version code. Giving ourselves 100,000 values [0, 99999]
        defaultConfig.versionCode = 123
    
        flavorDimensions "api", "abi"
    
        productFlavors {
            gingerbread {
                flavorDimension "api"
                minSdkVersion 10
                versionCode = 1
            }
            icecreamSandwich {
                flavorDimension "api"
                minSdkVersion 14
                versionCode = 2
            }
            x86 {
                flavorDimension "abi"
                ndk {
                    abiFilter "x86"
                }
                // this is the flavor part of the version code.
                // It must be higher than the arm one for devices supporting
                // both, as x86 is preferred.
                versionCode = 3
            }
            arm {
                flavorDimension "abi"
                ndk {
                    abiFilter "armeabi-v7a"
                }
                versionCode = 2
            }
            mips {
                flavorDimension "abi"
                ndk {
                    abiFilter "mips"
                }
                versionCode = 1
            }
            fat {
                flavorDimension "abi"
                // fat binary, lowest version code to be
                // the last option
                versionCode = 0
            }
        }
    
        // make per-variant version code
        applicationVariants.all { variant ->
            // get the version code of each flavor
            def apiVersion = variant.productFlavors.get(0).versionCode
            def abiVersion = variant.productFlavors.get(1).versionCode
    
            // set the composite code
            variant.mergedFlavor.versionCode = apiVersion * 1000000 + abiVersion * 100000 + defaultConfig.versionCode
        }
    
    }

Beachten Sie, dass dadurch Ihre Android.mk- und Application.mk-Dateien ignoriert werden. Um dieses Problem zu umgehen, können Sie gradle anweisen, den atuomatischen ndk-Build-Aufruf zu deaktivieren und dann das Verzeichnis für ndk-Quellen manuell anzugeben.

sourceSets.main {
    jniLibs.srcDir 'src/main/libs' // use the jni .so compiled from the manual ndk-build command
    jni.srcDirs = [] //disable automatic ndk-build call
}

Außerdem möchten Sie wahrscheinlich ndk-build in Ihrem Gradle-Build-Skript explizit aufrufen, da Sie gerade den automatischen Aufruf deaktiviert haben.

task ndkBuild(type: Exec) {
   commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn ndkBuild
}

Ja. Dies funktioniert jedoch nur unter Unix-Plattformen und ist auch dann eingeschränkt, wenn Sie eine komplexere als sehr einfache ndk-Konfiguration / Makefiles verwenden.
Plaisthos

Ja, es werden automatisch Makefiles für die begrenzten Dinge generiert, die Sie in der Gradle-Build-Datei festlegen können. Es gibt jedoch eine Problemumgehung. Ich habe es meiner Antwort hinzugefügt.
Cypress Frankenfeld

1
Der Aufruf von ndk-build funktioniert nur über die Befehlszeile, nicht über Android Studio.
Cameron Lowell Palmer

Obwohl dies nicht die aktuellste Antwort ist, scheint sie wahrscheinlich die genaueste zu sein. Achten Sie besonders auf Schritt 3: "Laden Sie die neuesten Gradle-Beispielprojekte herunter ".
Sean Beach

4
Ich benutze diesen Hack, anstatt src dir zu deaktivieren, damit ich c / c ++ - Dateien innerhalb des idetasks.all { task -> if (task.name.contains('Ndk')) task.enabled = false }
sherpya

23

Ich fand, dass "gradle 1.11 com.android.tools.build:gradle:0.9.+" jetzt Pre-Build ndk unterstützt. Sie können einfach die * .so in das Verzeichnis src / main / jniLibs einfügen. Beim Bau von Gradle wird der ndk an der richtigen Stelle verpackt.

Hier ist mein Projekt

Projekt:
| --src
| - | --main
| - | - | --java
| - | - | --jniLibs
| - | - | - | --armeabi
| - | - | - | - | -. also Dateien
| --libs
| - | --other.jar


16

Ab sofort (Android Studio v0.8.6) ist es ganz einfach. Hier sind die Schritte zum Erstellen einer App vom Typ "Hallo Welt":

  1. Laden Sie das Android NDK herunter und legen Sie den Stammordner an einem vernünftigen Ort ab - möglicherweise am selben Speicherort wie der SDK-Ordner.

  2. Fügen Sie Ihrer local.propertiesDatei Folgendes hinzu : ndk.dir=<path-to-ndk>

  3. Fügen Sie Ihrer build.gradle-Datei innerhalb des defaultConfigVerschlusses direkt nach der versionNameZeile Folgendes hinzu:ndk { moduleName="hello-world" }

  4. mainErstellen Sie im Verzeichnis Ihres App-Moduls einen neuen Ordner mit dem Namen jni.

  5. Erstellen hello-world.cSie in diesem Ordner eine Datei mit dem Namen , die Sie unten sehen werden.

  6. Im folgenden Beispielcode finden Sie Activityein Beispiel für den Aufruf einer Methode (oder ist es eine Funktion?) In hello-world.c.


hello-world.c

#include <string.h>
#include <jni.h>

jstring
Java_me_mattlogan_ndktest_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz)
{
    return (*env)->NewStringUTF(env, "Hello world!");
}

MainActivity.java

public class MainActivity extends Activity {

    static {
        System.loadLibrary("hello-world");
    }

    public native String stringFromJNI();

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

        String testString = stringFromJNI();

        TextView mainText = (TextView) findViewById(R.id.main_text);
        mainText.setText(testString);
    }
}

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "me.mattlogan.ndktest"
        minSdkVersion 15
        targetSdkVersion 20
        versionCode 1
        versionName "1.0"

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

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Den vollständigen Quellcode einer sehr ähnlichen App finden Sie hier (abzüglich des NDK).


Ich mache genau das, was ich in meinem aktuellen Projekt angegeben habe, aber das NDK-Zeug wird immer noch nicht gebaut. Irgendwelche Ideen? Es scheint, als würde es alles andere bauen, aber nur das jni-Zeug überspringen.
Alice.Harrison

@NannuoLei danke, ich habe es versucht, aber ich bekomme ein Problem, bei dem die .so nicht generiert werden. Alles andere scheint zu funktionieren, aber wenn ich das apkg im Emulator starte, beschwert es sich, dass es das gemeinsam genutzte Objekt nicht laden kann.
aaa90210

@ aaa90210 basiert Ihr Emulator auf einem x86-Image? Standardmäßig erstellt NDK nur eine ARMEABI-Bibliothek. Wenn Sie ein x86-Image erstellen möchten, können Sie diese Zeile in Application.mk einfügen: APP_ABI: = armeabi x86
Leo unterstützt Monica Cellio am

1
es hat bei mir funktioniert. PS: Java_me_mattlogan_ndktest_MainActivity_stringFromJNI
Wer

8

Wenn Sie unter Unix arbeiten, fügt die neueste Version (0.8) ndk-build hinzu. So fügen Sie es hinzu:

android.ndk {
    moduleName "libraw"
}

Es wird erwartet, dass die JNI unter 'src / main / jni' gefunden wird, andernfalls können Sie sie definieren mit:

sourceSets.main {
    jni.srcDirs = 'path'
}

Ab dem 28. Januar 2014 mit Version 0.8 ist der Build unter Windows fehlerhaft. Sie müssen den Build deaktivieren mit:

sourceSets.main {
    jni.srcDirs = [] //disable automatic ndk-build call (currently broken for windows)
}

1
Gibt es eine Dokumentation zu dieser Funktion? Ich konnte keine finden. Im Moment scheint das meine Android.mk/Application.mk völlig zu ignorieren.
Plaisthos

Ich habe keine gefunden. Möglicherweise hat es sich halbgebacken in den Build geschlichen. Ich bin unter Windows, daher kann ich nur bestätigen, dass es beim Versuch, das Unix-Skript ndk-build aufzurufen, fehlschlägt. Es würde keinen anderen Grund geben, dies zu nennen, als native Kompilierung in Gradle zu integrieren. Bist du in Unix?
Anthony


Es wird erwartet, dass vorgefertigte * .so-Dateien in jniLibs.srcDirs
Alpine

Ich würde aufgrund der Tatsache, dass es beim Aufrufen von ndk-build abstürzt, nicht zustimmen, was absolut nicht notwendig ist, wenn es gebaute Bibliotheken erfordert. Ich kann es nicht bestätigen, da ich momentan keine Zeit für VM Linux habe.
Anthony

7

Eine elegante Problemumgehung finden Sie unter https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J .

Grundsätzlich erstellen Sie ein Glas, das "lib / armeabi / yourlib.so" enthält, und fügen das Glas dann in den Build ein.


Ja. Das funktioniert nur gut, wenn Sie Ihren Code nicht oft ändern. Und Sie müssen binäre JAR-Dateien in das Repository aufnehmen. Andernfalls erhalten Sie ein Build-Skript, das im laufenden Betrieb ein JAR erstellt.
Plaisthos

1
Ich habe Android Hallo-JNI Beispiel modifiziert mit einem einfachen Bash - Skript , dass Wraps ndk-build, erzeugt .jars für jeden .sound legt sie in gradle Erstellungspfad diesen Schmerz zu lindern. Hör zu.
dbro

4

Eine gute Antwort zur Automatisierung des .soPackens von leicht kompilierbaren Dateien finden Sie in einem anderen (geschlossenen) Thread . Damit das funktioniert, musste ich die Zeile ändern:

from fileTree(dir: 'libs', include: '**/*.so')

in:

from fileTree(dir: 'src/main/libs', include: '**/*.so') 

Ohne diese Änderung wurden die .soDateien nicht gefunden und die Aufgabe zum Packen würde daher niemals ausgeführt.


Update: Bitte beachten Sie, dass in den neueren Android Studios (mindestens in Version 1.5) der native Code viel besser integriert ist und es nicht erforderlich ist, diese separate Aufgabe zum Packen Ihres Codes auszuführen.
HYS

4

Die Antwort von @plaisthos wurde in der neuesten Gradle-Version veröffentlicht, aber es gibt immer noch eine Möglichkeit, dies zu tun. Erstellen Sie ein native-libsVerzeichnis im Stammverzeichnis Ihres Projektverzeichnisses und kopieren Sie alle Ihre Bibliotheken in dieses Verzeichnis.

Fügen Sie Ihrem build.gradle die folgenden Zeilen hinzu. Bauen und glücklich sein.

task copyNativeLibs(type: Copy) {
    from(new File(project(':<your project>').getProjectDir(), 'native-libs')) { include '**/*.so' }
    into new File(buildDir, 'native-libs')
}

tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }

clean.dependsOn 'cleanCopyNativeLibs'

3

Dies ist der Code, den ich benutze, um mit android-ndk von gradle zu erstellen. Fügen Sie dazu den ndk-Verzeichnispfad in gradle.propertiesdh hinzu. ndkdir=/home/user/android-ndk-r9dFügen Sie alle jni-Dateien hinzu und legen Sie sie in einem Ordner nativeab, src/main/wie Sie anhand des unten angegebenen Codes sehen können. Es wird ein Jar mit nativen Bibliotheken erstellt, die Sie normalerweise wie in verwenden könnenSystem.loadLibrary("libraryname");

dependencies {
    compile fileTree(dir: "$buildDir/native-libs", include: '*.jar')
}

task ndkBuild(type: Exec) {
    commandLine "$ndkdir/ndk-build", "--directory", "$projectDir/src/main/native", '-j', Runtime.runtime.availableProcessors(),
            "APP_PLATFORM=android-8",
            "APP_BUILD_SCRIPT=$projectDir/src/main/native/Android.mk",
            "NDK_OUT=$buildDir/native/obj",
            "NDK_APP_DST_DIR=$buildDir/native/libs/\$(TARGET_ARCH_ABI)"
}

task nativeLibsToJar(type: Jar, description: 'create a jar with native libs') {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    from fileTree(dir: "$buildDir/native/libs", include: '**/*.so')
    into 'lib/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn nativeLibsToJar
}

nativeLibsToJar.dependsOn 'ndkBuild'

3

Ich habe den folgenden Code zum Kompilieren nativer Dropbox-Bibliotheken verwendet. Ich verwende Android Studio v1.1.

task nativeLibsToJar(type: Zip) {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    extension 'jar'
    from fileTree(dir: 'src/main/libs', include: '**/*.so')
    into 'lib/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn(nativeLibsToJar)
}


1

Um das zu erweitern, was Naxos gesagt hat (Danke, Naxos, dass Sie mich in die richtige Richtung geschickt haben!), Habe ich aus den kürzlich veröffentlichten NDK-Beispielen einiges gelernt und hier eine Antwort in einer ähnlichen Frage gepostet.

So konfigurieren Sie NDK mit dem Android Gradle Plugin 0.7

Dieser Beitrag enthält ausführliche Informationen zum Verknüpfen vorgefertigter nativer Bibliotheken mit Ihrer App für die verschiedenen Architekturen sowie Informationen zum direkten Hinzufügen von NDK-Unterstützung zum Skript build.gradle. Zum größten Teil sollten Sie die Arbeit um Zip und Kopieren nicht mehr erledigen müssen.


1

Hier sind die Schritte, mit denen ich das NDK in meinem Android Studio-Projekt zum Laufen gebracht habe. Ich habe dieses Tutorial verwendet, um https://software.intel.com/en-us/videos/using-the-ndk-with-android-studio zu unterstützen

Um NDK verwenden zu können, müssen Sie local.properties eine NDK-Zeile hinzufügen. Also unter deiner sdk.dir hinzufügen

ndk.dir=C\:\\MyPathToMyNDK\ndk

In meinen Apps build.gradle habe ich den folgenden Code

        ndk {
            moduleName "myLib"
            ldLibs "log"
            stl "gnustl_shared"
            cFlags "-std=c++11 -frtti -fexceptions -pthread"
        }

Modulname ist der Name, den Sie Ihrem nativen Code geben möchten. Ich glaube, so wird die gemeinsam genutzte Bibliothek heißen. Mit ldLibs kann ich mich bei LogCat anmelden. STL ist die STL, die Sie importieren möchten. Es gibt viele Optionen, genau wie beim Eclipse NDK. ( http://www.kandroid.org/ndk/docs/CPLUSPLUS-SUPPORT.html )

cFlags sind für mich immer noch eine gewisse Menge schwarzer Magie. Ich habe keine gute Quelle für alle Optionen gefunden und was sie mir geben. Suchen Sie in StackOverflow nach allem, was Sie brauchen. Dort habe ich es gefunden. Ich weiß, dass ich mit c ++ 11 den neuen c ++ 11-Standard verwenden kann.

Hier ist ein Beispiel, wie ich mich vom nativen Code bei LogCat anmelde

__android_log_print(ANDROID_LOG_DEBUG, "TestApp", "Adding - String %d has a field name of %s and a value of %s", i, lKeyUTF8.c_str(), lValueUTF8.c_str());

1

Projekt in Android Studio von Eclipse aus konfigurieren : Sie müssen das Eclipse-ndk-Projekt in Android Studio importieren, ohne es in Gradle zu exportieren, und es funktioniert. Außerdem müssen Sie den Pfad von ndk in local.properties hinzufügen . Wenn ein Fehler angezeigt wird , fügen Sie ihn hinzu

sourceSets.main {
        jniLibs.srcDir 'src/main/libs' 
        jni.srcDirs = [] //disable automatic ndk-build callenter code here
    }

in build.gradle Datei dann erstellen jni Ordner- und Datei mit Terminal und führen Sie es funktioniert


1
Siehe siehe meine eigene Antwort. Das ist die Problemumgehung, die ich derzeit verwende, aber es ist keine wirkliche Lösung.
Plaisthos

1

Jetzt, da sich Android Studio im stabilen Kanal befindet, ist es ziemlich einfach, die Android-Ndk-Beispiele zum Laufen zu bringen. Diese Beispiele verwenden das experimentelle Plugin ndk und sind neuer als die in der Online-Dokumentation zu Android NDK verlinkten. Sobald Sie wissen, dass sie funktionieren, können Sie die Dateien build.gradle, local.properties und gradle-wrapper.properties studieren und Ihr Projekt entsprechend ändern. Im Folgenden finden Sie die Schritte, um sie zum Laufen zu bringen.

  1. Gehen Sie zu Einstellungen, Aussehen und Verhalten, Systemeinstellungen, Android SDK, wählen Sie die Registerkarte SDK-Tools und überprüfen Sie Android NDK Version 1.0.0 am Ende der Liste. Dadurch wird das NDK heruntergeladen.

  2. Zeigen Sie auf den Speicherort des neu heruntergeladenen NDK. Beachten Sie, dass es im Verzeichnis sdk / ndk-bundle abgelegt wird. Wählen Sie dazu Datei, Projektstruktur, SDK-Speicherort (links) und geben Sie einen Pfad unter Android NDK-Speicherort ein. Dadurch wird ein ndk-Eintrag zu local.properties hinzugefügt, der dem folgenden ähnelt:

    Mac / Linux: ndk.dir = / Android / sdk / ndk-Bundle
    Windows: ndk.dir = C: \ Android \ sdk \ ndk-Bundle

Ich habe alle Projekte im Repository auf diese Weise erfolgreich erstellt und bereitgestellt, mit Ausnahme von gles3gni, nativem Codec und Builder. Ich benutze folgendes:

Android Studio 1.3 Build AI-141.2117773
Android-Ndk-Beispiele veröffentlicht am 28. Juli 2015 (Link oben)
SDK-Tools 24.3.3
NDK r10e extrahiert in C: \ Android \ sdk \ ndk-Bundle
Gradle 2.5
Gradle-Plugin 0.2.0
Windows 8.1 64-Bit


1

NDK Builds und Gradle (Basic)

Im Allgemeinen ist das Erstellen mit dem NDK so einfach wie das korrekte Angeben eines ndkBuild-Pfads zu Android.mk oder eines cmake-Pfads zu CMakeLists.txt. Ich empfehle CMake gegenüber dem älteren Android.mk, da die C / C ++ - Unterstützung von Android Studio auf CLion basiert und CMake als Projektformat verwendet. Dies hat meiner Erfahrung nach dazu geführt, dass die IDE bei größeren Projekten schneller reagiert. Alles, was in Ihrem Projekt kompiliert wurde, wird automatisch erstellt und in die APK kopiert.

apply plugin: 'com.android.library'

android {
    compileSdkVersion 19
    buildToolsVersion "25.0.2"

    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 19

        ndk {
            abiFilters 'armeabi', 'armeabi-v7a', 'x86'
            // 64-bit support requires an Android API level higher than 19; Namely 21 and higher
            //abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }

        externalNativeBuild {
            cmake {
                arguments '-DANDROID_TOOLCHAIN=clang',
                        '-DANDROID_PLATFORM=android-19',
                        '-DANDROID_STL=gnustl_static',
                        '-DANDROID_ARM_NEON=TRUE'

            }
        }
    }

    externalNativeBuild {
        cmake {
            path 'src/main/jni/CMakeLists.txt'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

Hinzufügen vorgefertigter Bibliotheken zum Projekt (erweitert)

Statische Bibliotheken (.a) in Ihrem NDK-Build werden automatisch aufgenommen, vorgefertigte dynamische Bibliotheken (.so) müssen jedoch abgelegt werden jniLibs. Dies kann mit konfiguriert werden sourceSets, aber Sie sollten den Standard übernehmen. Sie benötigen keine zusätzlichen Befehle, build.gradlewenn Sie vorgefertigte Bibliotheken einschließen.

Das Layout von jniLibs

Weitere Informationen zur Struktur finden Sie im Android Gradle Plugin Benutzerhandbuch .

|--app:
|--|--build.gradle
|--|--src:
|--|--|--main
|--|--|--|--java
|--|--|--|--jni
|--|--|--|--|--CMakeLists.txt
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--.so Files
|--|--|--|--|--armeabi-v7a
|--|--|--|--|--|--.so Files
|--|--|--|--|--x86
|--|--|--|--|--|--.so Files

Sie können dann überprüfen, ob die resultierende APK Ihre .so-Dateien enthält, normalerweise unter build/outputs/apk/, unzip -l myApp.apkum den Inhalt aufzulisten .

Gemeinsame Bibliotheken erstellen

Wenn Sie eine gemeinsam genutzte Bibliothek im NDK erstellen, müssen Sie nichts weiter tun. Es wird korrekt in der APK gebündelt.


0

Fügen Sie einfach diese Zeilen zur App hinzu build.gradle

dependencies {
    ...
    compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
}

task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    extension 'jar'
    from fileTree(dir: 'libs', include: '**/*.so')
    into 'lib/armeabi/'
}

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn(nativeLibsToJar)
}

Ich denke, der Ansatz von jniLibs.srcDirs ist sauberer als dieser, da Sie abiFilter / flavours verwenden können, aber Ihr Ansatz sollte auch funktionieren.
Plaisthos

0

Ich kann den so Erfolg laden!

1. Fügen Sie die .so-Datei zu diesem Pfad hinzu

Project:

| --src | - | --main | - | - | --java | - | - | --jniLibs | - | - | - | --armeabi | - | - | - | - | -. also Dateien

2. Fügen Sie diesen Code zu gradle.build hinzu

android {
splits {
    abi {
        enable true
        reset()
        include 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a', 'armeabi'
        universalApk false
    }
}

}}

3.System.loadLibrary("yousoname");

  1. viel glück für dich, es ist ok mit gradle 1.2.3

0
  1. Wenn Ihr Projekt aus Eclipse exportiert wurde, fügen Sie die folgenden Codes in die Gradle-Datei ein:

    android {
       sourceSets{
            main{
               jniLibs.srcDir['libs']  
          }  
        }
    }

2.Wenn Sie ein Projekt in Android Studio erstellen:

Erstellen Sie einen Ordner mit dem Namen jniLibs in src / main / , und legen Sie Ihre * .so-Dateien im Ordner jniLibs ab.

Und kopieren Sie den Code wie folgt in Ihre Gradle-Datei:

android {
    sourceSets{  
       main{  
         jniLibs.srcDir['jniLibs']  
      }  
    }
}

0

Während ich glaube, dass SJoshi (Orakel-Typ) die vollständigste Antwort hat, ist das SWIG-Projekt ein Sonderfall, interessant und nützlich, aber nicht verallgemeinert für die Mehrheit der Projekte, die mit den Standard-SDK-Ameisen-basierten Projekten + gut abgeschnitten haben NDK. Wir alle möchten jetzt höchstwahrscheinlich Android Studio verwenden oder möchten eine CI-freundlichere Build-Toolchain für Mobilgeräte, die gradle theoretisch bietet.

Ich habe meinen Ansatz veröffentlicht, von irgendwoher ausgeliehen (ich habe ihn auf SO gefunden, aber einen Kern für die App build.gradle veröffentlicht: https://gist.github.com/truedat101/c45ff2b69e91d5c8e9c7962d4b96e841 ). Kurz gesagt, ich empfehle Folgendes:

  • Aktualisieren Sie Ihr Projekt nicht auf den neuesten Gradle-Build
  • Verwenden Sie com.android.tools.build:gradle:1.5.0 in Ihrem Projektstamm
  • Verwenden Sie com.android.application in Ihrem App-Projekt
  • Stellen Sie sicher, dass gradle.properties Folgendes enthält: android.useDeprecatedNdk = true (falls es sich beschwert)
  • Verwenden Sie den oben beschriebenen Ansatz, um sicherzustellen, dass Ihre stundenlangen Bemühungen beim Erstellen von Android.mk-Dateien nicht weggeworfen werden. Sie steuern, welche Zielbögen erstellt werden sollen. Und diese Anweisungen sind freundlich zu Windows-Benutzern, die theoretisch in der Lage sein sollten, ohne besondere Probleme auf Windows aufzubauen.

Gradle für Android war meiner Meinung nach ein Chaos, genauso wie ich die geliehenen Maven-Konzepte und die meinungsgebundene Struktur von Verzeichnissen für ein Projekt mag. Diese NDK-Funktion ist seit fast 3 Jahren "in Kürze" verfügbar.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.