要在Android Studio中使用JNI,还需要对Gralde做一些配置文。这里需要对MyApplication/build.gradle
、MyApplication/gradle/wrapper/gradle-wrapper.properties
,和MyApplication/app/build.gradle
这几个文件做修改。
修改MyApplication/build.gradle
文件,最终的内容为:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
在这个文件中配置gradle插件的版本为gradle-experimental:0.7.0
。
修改MyApplication/gradle/wrapper/gradle-wrapper.properties
文件,最终的内容为:
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
在这个文件中配置gradle的版本。
修改MyApplication/app/build.gradle
文件,最终的内容为:
apply plugin: 'com.android.model.application'
model {
repositories {
libs(PrebuiltLibraries) {
chromium_net {
headers.srcDir "src/main/jni/third_party/chromium/include"
binaries.withType(SharedLibraryBinary) {
sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libnet.cr.so")
}
}
chromium_base {
headers.srcDir "src/main/jni/third_party/chromium/include"
binaries.withType(SharedLibraryBinary) {
sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/libbase.cr.so")
}
}
chromium_url {
headers.srcDir "src/main/jni/third_party/chromium/include"
binaries.withType(SharedLibraryBinary) {
sharedLibraryFile = file("src/main/jni/third_party/chromium/libs/${targetPlatform.getName()}/liburl.cr.so")
}
}
}
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.example.hanpfei0306.myapplication"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 21
versionCode 1
versionName "1.0"
}
ndk {
moduleName "neteasenet"
toolchain "clang"
CFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include/'),])
cppFlags.addAll(["-std=gnu++11", ])
cppFlags.addAll(["-DV8_DEPRECATION_WARNINGS",
"-DENABLE_NOTIFICATIONS",
"-DENABLE_BROWSER_CDMS",
"-DENABLE_PRINTING=1",
"-DENABLE_BASIC_PRINTING=1",
"-DENABLE_SPELLCHECK=1",
"-DUSE_BROWSER_SPELLCHECKER=1",
"-DUSE_OPENSSL_CERTS=1",
"-DNO_TCMALLOC",
"-DUSE_EXTERNAL_POPUP_MENU=1",
"-DDISABLE_NACL",
"-DENABLE_SUPERVISED_USERS=1",
"-DCHROMIUM_BUILD",
"-D_FILE_OFFSET_BITS=64",
"-DANDROID",
"-DHAVE_SYS_UIO_H",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D_FORTIFY_SOURCE=2",
"-DCOMPONENT_BUILD",
"-D__GNU_SOURCE=1",
"-D_DEBUG",
"-DDYNAMIC_ANNOTATIONS_ENABLED=1",
"-DWTF_USE_DYNAMIC_ANNOTATIONS=1",
"-DDLOPEN_KERBEROS",
"-DNET_IMPLEMENTATION",
"-DUSE_KERBEROS",
"-DENABLE_BUILT_IN_DNS",
"-DPOSIX_AVOID_MMAP",
"-DENABLE_WEBSOCKETS",
"-DGOOGLE_PROTOBUF_NO_RTTI",
"-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
"-DHAVE_PTHREAD",
"-DPROTOBUF_USE_DLLS",
"-DBORINGSSL_SHARED_LIBRARY",
"-DU_USING_ICU_NAMESPACE=0",
"-DU_ENABLE_DYLOAD=0",
])
cppFlags.addAll(['-I' + file('src/main/jni/third_party/chromium/include'), ])
ldLibs.add("android")
ldLibs.add("log")
ldLibs.add("z")
stl "c++_shared"
}
sources {
main {
java {
source {
srcDir "src/main/java"
}
}
jni {
source {
srcDirs = ["src/main/jni",]
}
dependencies {
library 'chromium_base' linkage 'shared'
library 'chromium_url' linkage 'shared'
library 'chromium_net' linkage 'shared'
}
}
jniLibs {
source {
srcDirs =["src/main/jni/third_party/chromium/libs",]
}
}
}
}
buildTypes {
debug {
ndk {
abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
}
}
release {
minifyEnabled false
proguardFiles.add(file("proguard-rules.pro"))
ndk {
abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
}
关键点主要有如下这些:
$ gn desc out/Default/ net
Target //net:net
Type: shared_library
Toolchain: //build/toolchain/android:arm
......
cflags
-fno-strict-aliasing
--param=ssp-buffer-size=4
-fstack-protector
-funwind-tables
-fPIC
-pipe
-ffunction-sections
-fno-short-enums
-finline-limit=64
-march=armv7-a
-mfloat-abi=softfp
-mthumb
-mthumb-interwork
-mtune=generic-armv7-a
-fno-tree-sra
-fno-caller-saves
-mfpu=neon
-Wall
-Werror
-Wno-psabi
-Wno-unused-local-typedefs
-Wno-maybe-uninitialized
-Wno-missing-field-initializers
-Wno-unused-parameter
-Os
-fomit-frame-pointer
-fno-ident
-fdata-sections
-ffunction-sections
-g1
--sysroot=../../../../../../../~/dev_tools/Android/android-ndk-r12b/platforms/android-16/arch-arm
-fvisibility=hidden
cflags_cc
-fno-threadsafe-statics
-fvisibility-inlines-hidden
-std=gnu++11
-Wno-narrowing
-fno-rtti
-isystem../../../../../../../~/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libcxx/include
-isystem../../../../../../../~/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++abi/libcxxabi/include
-isystem../../../../../../../~/dev_tools/Android/android-ndk-r12b/sources/android/support/include
-fno-exceptions
......
defines
V8_DEPRECATION_WARNINGS
ENABLE_NOTIFICATIONS
ENABLE_BROWSER_CDMS
ENABLE_PRINTING=1
ENABLE_BASIC_PRINTING=1
ENABLE_SPELLCHECK=1
USE_BROWSER_SPELLCHECKER=1
USE_OPENSSL_CERTS=1
NO_TCMALLOC
USE_EXTERNAL_POPUP_MENU=1
ENABLE_WEBRTC=1
DISABLE_NACL
ENABLE_SUPERVISED_USERS=1
VIDEO_HOLE=1
SAFE_BROWSING_DB_REMOTE
CHROMIUM_BUILD
ENABLE_MEDIA_ROUTER=1
ENABLE_WEBVR
FIELDTRIAL_TESTING_ENABLED
_FILE_OFFSET_BITS=64
ANDROID
HAVE_SYS_UIO_H
ANDROID_NDK_VERSION=r10e
__STDC_CONSTANT_MACROS
__STDC_FORMAT_MACROS
_FORTIFY_SOURCE=2
COMPONENT_BUILD
__GNU_SOURCE=1
NDEBUG
NVALGRIND
DYNAMIC_ANNOTATIONS_ENABLED=0
DLOPEN_KERBEROS
NET_IMPLEMENTATION
USE_KERBEROS
ENABLE_BUILT_IN_DNS
POSIX_AVOID_MMAP
ENABLE_WEBSOCKETS
GOOGLE_PROTOBUF_NO_RTTI
GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
HAVE_PTHREAD
PROTOBUF_USE_DLLS
BORINGSSL_SHARED_LIBRARY
U_USING_ICU_NAMESPACE=0
U_ENABLE_DYLOAD=0
U_NOEXCEPT=
ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE
......
libs
c++_shared
~/dev_tools/Android/android-ndk-r12b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/libgcc.a
c
atomic
dl
m
log
unwind
lib_dirs
~/dev_tools/Android/android-ndk-r12b/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/
主要是build.gradle的cppFlags添加的那些宏定义,它们来自defines。如果这些配置,在编译chromium net so的环境,和构建我们的工程的环境之间存在差异,则很可能会导致运行期一些莫名奇妙的问题,比如意外的缓冲区溢出之类的。
如我们前面提到的,Chromium已经有提供一个称为cronet的模块,封装chromium net,提供Java接口。使用这个模块将大大简化我们的移植工作。构建cronet所需步骤主要有:
out/Default/args.gn
,编辑该文件将is_component_build
配置选项置为false。执行如下命令:
$ gn gen out/Default
产生ninja构建所需的 .ninja 文件。
执行如下命令生成cronet so文件:
$ ninja -C out/Default/ cronet
并将产生的libcronet.so文件导入我们的应用中。我们的应用的build.gradle将如下面这样:
apply plugin: 'com.android.model.library'
model {
android {
compileSdkVersion 16
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion.apiLevel 15
targetSdkVersion.apiLevel 19
versionCode 1
versionName "1.0"
}
sources {
main {
jniLibs {
source {
srcDirs =["src/main/jni/jniLibs/",]
}
}
}
}
buildTypes {
debug {
ndk {
abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
}
}
release {
minifyEnabled false
proguardFiles.add(file("proguard-rules.pro"))
ndk {
abiFilters.add("armeabi")
abiFilters.add("armeabi-v7a")
}
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-annotations:20.0.0'
testCompile 'junit:junit:4.12'
}
执行如下命令生成cronet Java层代码的jar包:
$ ninja -C out/Default/ cronet_java
这将在out/Default/lib.java/的子目录下产生出多个jar文件,cronet_java.jar,cronet_api.jar,url_java.jar,base_java.jar,net_java.jar。将这些jar文件全部导入我们的应用中。
调用cronet提供的Java接口执行网络请求:
package com.netease.netlib;
import android.content.Context;
import org.chromium.net.CronetEngine;
import org.chromium.net.UploadDataProviders;
import org.chromium.net.UrlRequest;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Created by hanpfei0306 on 16-8-15.
*/
public class CronetUtils {
private static final String TAG = "CronetUtils";
private static CronetUtils sInstance;
private CronetEngine mCronetEngine;
private Executor mExecutor = Executors.newCachedThreadPool();
private CronetUtils() {
}
public static synchronized CronetUtils getsInstance() {
if (sInstance == null) {
sInstance = new CronetUtils();
}
return sInstance;
}
public synchronized void init(Context context) {
if (mCronetEngine == null) {
CronetEngine.Builder builder = new CronetEngine.Builder(context);
builder.
enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY,
100 * 1024)
.enableHttp2(true)
.enableQuic(true)
.enableSDCH(true)
.setLibraryName("cronet");
mCronetEngine = builder.build();
}
}
public void getHtml(String url, UrlRequest.Callback callback) {
startWithURL(url, callback);
}
private void startWithURL(String url, UrlRequest.Callback callback) {
startWithURL(url, callback, null);
}
private void startWithURL(String url, UrlRequest.Callback callback, String postData) {
UrlRequest.Builder builder = new UrlRequest.Builder(url, callback, mExecutor, mCronetEngine);
applyPostDataToUrlRequestBuilder(builder, mExecutor, postData);
builder.build().start();
}
private void applyPostDataToUrlRequestBuilder(
UrlRequest.Builder builder, Executor executor, String postData) {
if (postData != null && postData.length() > 0) {
builder.setHttpMethod("POST");
builder.addHeader("Content-Type", "application/x-www-form-urlencoded");
builder.setUploadDataProvider(
UploadDataProviders.create(postData.getBytes()), executor);
}
}
}
Done。
网易云新用户大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者韩鹏飞授权发布。