Issue
I have a large library of C files that relies on OpenSSL and I'm very new to working with native libraries, and especially new to working with android. I've managed to implement this library on iOS with no problems.
I've been looking around online for tutorials / information on how to do this, but so far I haven't found anything I can understand. It's all very confusing to me.
Essentially I'm trying to figure out how to compile the library of C files into a native lib using NDK and use the compiled library with imy android application.
From what I understand, I need a custom cmake file for android itself, but I don't know where to start with that and the documentation I've found has been incredibly difficult to follow.
So, I need some help understanding what the process would be of compiling the library in the following manor:
- Compile the library, linking it with openssl and libcrypto, using Gradle and CMakeLists.txt and link the final library with my Android Studio project.
- Be able to make calls to the native functions within these libraries from my Java code. (I understand that this requires a JNI Java Wrapper)
(I've already managed to build libssl and libcrypto for all archs that android requires, but I'm not sure what to do with the .a
/.so
files.)
Any help on this matter would be incredibly appreciated.
Thanks
EDIT:
I managed to generate some library files with the following.
File Structure:
.idea
app
build
gradle
jni <--- I made this folder specifically fo this.
Android.mk <-- This is the important file.
include
openssl
<openssl header files>
libs
arm64-v8a
libcrypto.a
libcrypto.so
libssl.a
libssl.so
armeabi
libcrypto.a
libcrypto.so
libssl.a
libssl.so
armeabi--v7a
libcrypto.a
libcrypto.so
libssl.a
libssl.so
mips
libcrypto.a
libcrypto.so
libssl.a
libssl.so
mips64
libcrypto.a
libcrypto.so
libssl.a
libssl.so
x86
libcrypto.a
libcrypto.so
libssl.a
libssl.so
x86_64
libcrypto.a
libcrypto.so
libssl.a
libssl.so
src <--- These are example files that i used to build this with.
myc_files.c
myother_c_files.c
myc_heades.h
myother_c_headers.h
I then used the following in the Android.mk to generate some libraries by running ndk-build
.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Select from arm64-v8a armeabi armeabi-v7a mips mips64 x86 x86_64
ARCH := armeabi
APP_UNIFIED_HEADERS := true
#APP_ABI := $(ARCH)
# TARGET_ARCH := $(ARCH)
TARGET_PLATFORM := android-14
SRC_DIR := $(LOCAL_PATH)/src
HDR_DIR := $(LOCAL_PATH)/include
LIB_DIR := $(LOCAL_PATH)/libs
LOCAL_C_INCLUDES := $(HDR_DIR)
LOCAL_MODULE := myclib
LOCAL_SRC_FILES := $(SRC_DIR)/myc_files.c $(SRC_DIR)/myother_c_files.c
LOCAL_LDLIBS += -L$(LIB_DIR)/$(ARCH) -lssl -lcrypto
include $(BUILD_STATIC_LIBRARY)
The libraries were put into PROJECT/obj/local
and I have no idea where to go from here, or if that Android.mk file actually properly built the libraries.
Solution
UPDATE: with AGP 4.0 (still not released), you can consume OpenSSL from maven.
dependencies {
implementation "com.android.ndk.thirdparty:openssl:1.1.1d-alpha-1"
}
In Android.mk, you simply add (at the end)
$(call import-module, prefab/curl)
Here are full details: https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html
Original answer:
0. Build openssl libraries for Android; you must choose the ABI (armeabi-v7a and x86 are usually enough). You can find the official tutorial long and boring. In this case, you can find prebuilt binaries on GitHub or elsewhere. Decide whether you want shared libs or static libs.
1. With Android Studio 2.3 you can build your library by the integrated externalNativeBuild gradle task. But you can build it separately, using
ndk-build
command.2. If you choose not to use gradle, copy the built shared libs to
app/src/main/jniLibs
directory of your Android project.3. You need a JNI wrapper to connect your Java code with C code. On the Java side, declare necessary native methods in one or more classes. These methods must be implemented on the C/C++ side, as described in the Android JNI walkthrough. Your Java code must explicitly load the shared library that includes these native method implementations. Note that you cannot directly call native functions in your library, or in opensssl library, even if these functions are exported.
The working Android.mk:
include $(CLEAR_VARS)
LOCAL_MODULE := vrazovpn
LOCAL_SRC_FILES := src/myc_files.c src/myother_c_files.c
LOCAL_STATIC_LIBRARIES := openssl libcrypto
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := openssl
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libssl.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcrypto
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)
few comments to clarify the above:
- LOCAL_SRC_FILES paths are relative to LOCAL_PATH.
- LOCAL_C_INCLUDE paths are relative to the working directory, that's why we often prefix them with
$(LOCAL_PATH)
. - It's OK to use LOCAL_C_INCLUDES to refer to headers that belong to some library that we use, but it is much safer and cleaner to export these headers with the library, using the power of LOCAL_EXPORT_C_INCLUDES; there are other settings that can be exported similarly.
Android.mk should not (and cannot) set the target ABI; it receives the target ABI from
ndk-build
. You can control which ABIs to include in build either by listing them in your Application.mk file or on the command line, e.g.ndk-build APP_ABI="x86 armeabi-v7a"
If you build your library in Android Studio 2.3 or above, using the gradle plugin, the APP_ABI
setting is ignored. You must specify the list in abiFilters.
Answered By - Alex Cohn
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.