1、背景介绍
最近有个项目,需要客户端发送短信,但是被360提示报毒了,还有一个问题就是不太安全,怎么办呢?这个时候,我们的处理方式是使用了JNI调用Java方法,来发送短信。但是在编译的过程中,出现了几个问题,这里来简单总结一下。
2、问题一
2.1 出错信息
这里直接贴出错误代码,以搜索引擎的强大,会很快就搜出来。
Android NDK: WARNING: APP_PLATFORM android-17 is larger than android:minSdkVersion 11 in ./AndroidManifest.xml [armeabi-v7a] Compile thumb : sendmsg <= sendmsg.c jni/sendmsg.c: In function 'Java_com_hello_jni_utils_JniUtils_sendSms': jni/sendmsg.c:14:23: error: request for member 'FindClass' in something not a structure or union jni/sendmsg.c:16:22: error: request for member 'GetStaticMethodID' in something not a structure or union jni/sendmsg.c:18:20: error: request for member 'NewObject' in something not a structure or union jni/sendmsg.c:21:8: error: request for member 'GetMethodID' in something not a structure or union jni/sendmsg.c:25:7: error: request for member 'CallVoidMethod' in something not a structure or union make.exe: *** [obj/local/armeabi-v7a/objs/sendmsg/sendmsg.o] Error 1
2.2 问题解析
这个错误当中,主要的问题是,找不到这个方法。但是我明明在系统中定义了该方法呀,哪里出错了呢?
我仔细检查了代码,发现代码并没有调用额外的方法,我在文件的头部也包含了相关头文件,如:
#include <jni.h> #include <string.h> #include <stdio.h>
后来发现一个问题,我是将这个文件用C++编译过的,没有问题。移植的时候,将系统使用了C文件命名,就出错了,那我再改回去行不行?好吧,测试通过,可行。
2.3 原因解析
深入分析之后,发现了是C语言语法格式与C++的差异导致的,如果是c程序,要用 (*env)->,如果是C++要用 env->。我在代码中,主要有这样的一个方法调用:
jobject sms = env->NewObject( smsclazz, get); jclass smsclazz = env->FindClass("android/telephony/SmsManager");
在linux下如果.c文件中用 “env->” 编译会找不到此结构,必须用“(*env)->”,或者改成.cpp文件,以 c++的方式来编译。
3、问题二
3.1 问题描述
在修改了2中的错误,再次编译的时候,发现一个问题,就是当我的文件修改成为了cpp文件之后,提示说c文件找不到,主要报错信息如下:
make.exe: *** No rule to make target `jni/sendmsg.c', needed by `obj/local/armeabi-v7a/objs/sendmsg/sendmsg.o'. Stop.
我挺纳闷的,我已经将c文件修改为cpp文件了呀,就算要提示,也应该提示cpp文件找不到才对呀。
3.2 解决方案猜测
好吧,是不是我的配置文件不对呢,我去检查了一下,我已经将文件修改为了cpp命名文件,如下:
LOCAL_SRC_FILES := sendmsg.cpp
我再仔细看看错误信息,说的是在make过程中,没有找到sendmsg.o文件。额,难道有缓存???将程序clean一下,出现一样的错误,暂时不去管他,看到目录下多出一个文件夹obj,如下:
3.3 解决方案
删掉obj文件,重新clean一下,OK!
4、问题三
4.1 问题描述
问题解决的差不多了,可是坑爹的又出现了一个问题,是什么呢?说是在链接的时候找不到这个方法,额,啥意思呀,我直接贴错误信息好了:
11-04 14:27:52.750: E/AndroidRuntime(27773): FATAL EXCEPTION: main 11-04 14:27:52.750: E/AndroidRuntime(27773): java.lang.UnsatisfiedLinkError: Native method not found: com.common.library.utils.JniUtils.sendSms:(Ljava/lang/String;Ljava/lang/String;)V 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.common.library.utils.JniUtils.sendSms(Native Method) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.paying.player.sms.SmsSendManager.sendSms(SmsSendManager.java:82) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.paying.player.sms.SmsSendManager.sendSms(SmsSendManager.java:115) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.paying.player.SplashActivity.sendSms(SplashActivity.java:98) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.paying.player.SplashActivity.onCreate(SplashActivity.java:47) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.Activity.performCreate(Activity.java:5184) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.qihoo360.mobilesafe.loader.b.callActivityOnCreate(SourceFile:81) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2078) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2139) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.ActivityThread.access$700(ActivityThread.java:143) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1241) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.os.Handler.dispatchMessage(Handler.java:99) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.os.Looper.loop(Looper.java:137) 11-04 14:27:52.750: E/AndroidRuntime(27773): at android.app.ActivityThread.main(ActivityThread.java:4963) 11-04 14:27:52.750: E/AndroidRuntime(27773): at java.lang.reflect.Method.invokeNative(Native Method) 11-04 14:27:52.750: E/AndroidRuntime(27773): at java.lang.reflect.Method.invoke(Method.java:511) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038) 11-04 14:27:52.750: E/AndroidRuntime(27773): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805) 11-04 14:27:52.750: E/AndroidRuntime(27773): at dalvik.system.NativeStart.main(Native Method)
4.2 解决方案
其实出现这个问题挺坑爹的,首先,我看了下,是否已经使用了static静态代码块,将编译之后的so文件包含进来?代码如下:
static { System.loadLibrary("sendmsg"); }
已经包含了呀,没问题。
那么,是不是参数列表不对呢?我仔细检查了一下,参数列表也没有问题。
再看,是不是参数的返回值有问题,导致程序除了问题呢?仔细看看,也没有问题(java代码和c++代码都没问题)。
坑爹了,到底什么地方出问题了,之前不是挺靠谱的么?我后来想起来,之前的时候用过一个头文件信息的,里面有一个继承c的语句,难道是这个问题?添加代码如下:
ok,编译成功。
4.3 成功信息
编译成功之后的信息,应该如下所示: