学习做一个使用NDK的小项目:
QQWry的格式和解析可以参考
http://hzy3774.iteye.com/blog/1851364
Github地址:https://github.com/hzy3774/AndroidIPQQWry
先设置好NDK编译器:
添加NDK编译器
设置编译器参数
*用java写好接口函数:
在C/C++将GBK转码成UTF-8比较麻烦,如果直接返回GBK的字符串在接口处会报错退出,所以直接传出字节数组。
QQWry.java:
public class QQWryAnd { private native void jniOpen(String datPath); private native byte[] jniGetVersionBytes(); private native byte[] jniGetIpAddrBytes(String ip); private native byte[] jniGetIpRangeBytes(String ip); private native int jniGetIpCount(); private native void jniClose(); }
用javah命令生成对应的本地函数,并填充:
qqand.cpp
#include "IPLocator.hpp" #ifdef __cplusplus extern "C" { #endif using namespace std; static jbyteArray string2jbyteArray(JNIEnv *env, string str); IPLocator* ipLocator; /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniOpen * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_com_hu_qqwryand_QQWryAnd_jniOpen (JNIEnv *env, jobject, jstring path){ const char* cpath = (const char*)env->GetStringUTFChars(path, NULL); LOGI("open file:\"%s\"", cpath); ipLocator = new IPLocator(cpath); env->ReleaseStringUTFChars(path, cpath); } /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniGetVersionBytes * Signature: ()[B */ JNIEXPORT jbyteArray JNICALL Java_com_hu_qqwryand_QQWryAnd_jniGetVersionBytes (JNIEnv *env, jobject){ string version = ipLocator->getVersion(); return string2jbyteArray(env, version); } /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniGetIpAddrBytes * Signature: (Ljava/lang/String;)[B */ JNIEXPORT jbyteArray JNICALL JNICALL Java_com_hu_qqwryand_QQWryAnd_jniGetIpAddrBytes (JNIEnv *env, jobject, jstring ip){ const char* cip = env->GetStringUTFChars(ip, NULL); string addr = ipLocator->getIpAddr(cip); return string2jbyteArray(env, addr); } /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniGetIpRangeBytes * Signature: (Ljava/lang/String;)[B */ JNIEXPORT jbyteArray JNICALL Java_com_hu_qqwryand_QQWryAnd_jniGetIpRangeBytes (JNIEnv *env, jobject, jstring ip){ const char* cip = env->GetStringUTFChars(ip, NULL); string range = ipLocator->getIpRange(cip); return string2jbyteArray(env, range); } /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniGetIpCount * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_hu_qqwryand_QQWryAnd_jniGetIpCount (JNIEnv *, jobject){ return (int)ipLocator->getTotal(); } /* * Class: com_hu_qqwryand_QQWryAnd * Method: jniClose * Signature: ()V */ JNIEXPORT void JNICALL Java_com_hu_qqwryand_QQWryAnd_jniClose (JNIEnv *, jobject){ LOGI("jniClose()"); delete ipLocator; ipLocator = 0; } static jbyteArray string2jbyteArray(JNIEnv *env, string str){ const char* cstr = str.c_str(); LOGI("string2jbyteArray(), len[%d]",strlen(cstr)); jbyteArray ret = env->NewByteArray(strlen(cstr)); env->SetByteArrayRegion(ret, 0, strlen(cstr), (jbyte*)cstr); return ret; } #ifdef __cplusplus } #endif
实现主要查询逻辑的IPLocator.cpp(来源于网络)
#include "IPLocator.hpp" #include <sstream> #include <stdlib.h> using std::cout; using std::cerr; using std::endl; using std::ios; IPLocator::IPLocator(const string& ipdb_name) { unsigned char buf[8]; ipdb.open(ipdb_name.c_str(),ios::binary); if(!ipdb) { cerr << "can not open " << ipdb_name <<endl; LOGE("can not open[%s]", ipdb_name.c_str()); return; } ipdb.read((char*)buf,8); first_index = IPLocator::bytes2integer(buf,4); last_index = IPLocator::bytes2integer(buf+4,4); index_count = (last_index - first_index) / 7 + 1; } IPLocator::~IPLocator() { ipdb.close(); } string IPLocator::getVersion() { string version = this->getIpAddr(0xffffff00); // std::ostringstream oss; // oss << this->index_count; // string total_item(oss.str()); // version = version + " 记录总数:" + total_item + "条"; return version; } unsigned int IPLocator::getTotal() { return this->index_count; } string IPLocator::getIpAddr(const string& ip) { return this->getIpAddr(this->getIpFromString(ip)); } string IPLocator::getIpAddr(unsigned int ip) { unsigned int M, L=0, R=this->index_count; string addr; while (L < R-1) { M = (L + R) / 2; this->setIpRange(M); if (ip == this->cur_start_ip) { L = M; break; } if (ip > this->cur_start_ip) L = M; else R = M; } this->setIpRange(L); /* version infomation, the last item */ // if((ip & 0xffffff00) == 0xffffff00) // this->setIpRange(R); if(ip >= this->cur_start_ip && ip <= this->cur_end_ip) addr = this->getAddr(this->cur_start_ip_offset); else // addr = "未找到该IP的地址"; addr = "Invalid IP"; return addr; } string IPLocator::getIpRange(const string& range) { return this->getIpRange(this->getIpFromString(range)); } string IPLocator::getIpRange(unsigned int range) { this->getIpAddr(range); return this->getIpString(this->cur_start_ip) + " - " + this->getIpString(this->cur_end_ip); } string IPLocator::getAddr(streamsize offset) { unsigned char byte; unsigned char buf[4]; unsigned int country_offset; string country_addr,area_addr; this->readFromFile(offset+4, buf,4); byte = buf[0]; if(0x01 == byte) { country_offset = IPLocator::bytes2integer(buf+1,3); this->readFromFile(country_offset,buf,4); byte = buf[0]; if(0x02 == byte){ country_addr = this->readStringFromFile(IPLocator::bytes2integer(buf+1,3)); area_addr = this->getAreaAddr(country_offset+4); } else { country_addr = this->readStringFromFile(country_offset); area_addr = this->getAreaAddr(country_offset+country_addr.length()+1); } } else if(0x02 == byte) { this->readFromFile(offset+4+1,buf,3); country_offset = IPLocator::bytes2integer(buf,3); country_addr = this->readStringFromFile(country_offset); area_addr = this->getAreaAddr(offset+4+4); } else { country_addr = this->readStringFromFile(offset+4); area_addr = this->getAreaAddr(offset+4+country_addr.length()+1); } return country_addr + " " + area_addr; } string IPLocator::getAreaAddr(streamsize offset) { unsigned char byte; unsigned char buf[4]; unsigned int p=0; string area_addr; this->readFromFile(offset,buf,4); byte = buf[0]; if(0x01 == byte || 0x02 == byte) { p = IPLocator::bytes2integer(buf+1,3); if(p) area_addr = this->readStringFromFile(p); else area_addr = ""; } else area_addr = this->readStringFromFile(offset); return area_addr; } void IPLocator::setIpRange(unsigned int rec_no) { unsigned char buf[7]; unsigned int offset = first_index + rec_no * 7; this->readFromFile(offset, buf, 7); this->cur_start_ip = IPLocator::bytes2integer(buf,4); this->cur_start_ip_offset = IPLocator::bytes2integer(buf+4,3); this->readFromFile(this->cur_start_ip_offset, buf, 4); this->cur_end_ip = IPLocator::bytes2integer(buf, 4); } void IPLocator::readFromFile( streamsize offset, unsigned char *buf, int len) { ipdb.seekg(offset); ipdb.read((char*)buf,len); } string IPLocator::readStringFromFile(streamsize offset) { char ch; string str; ipdb.seekg(offset); ipdb.get(ch); while(ch) { str += ch; ipdb.get(ch); } return str; } unsigned int IPLocator::getIpFromString(const string& ip) { char *result = NULL; unsigned int ret=0; char *s=strdup(ip.c_str()); result = strtok( s, "." ); while( result ) { ret <<= 8; ret |= (unsigned int)atoi(result); result = strtok( NULL, "." ); } free(s); return ret; } string IPLocator::getIpString(unsigned int ip) { char buf[256]; sprintf(buf,"%d.%d.%d.%d",ip>>24,(ip>>16)&0xff,(ip>>8)&0xff,ip&0xff ); string ipstr(buf); return ipstr; } unsigned int IPLocator::bytes2integer(unsigned char *ip, int count) { int i; unsigned int ret; if(count < 1 || count > 4) return 0; ret = ip[0]; for (i = 0; i < count; i++) ret |= ((unsigned int)ip[i])<<(8*i); return ret; }
头文件IPLocator.hpp
#include <jni.h> #include <android/log.h> #define LOG_TAG "jniLog" // 这个是自定义的LOG的标识 #undef LOG // 取消默认的LOG #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) // 定义LOG类型 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) // 定义LOG类型 #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) // 定义LOG类型 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // 定义LOG类型 #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__) // 定义LOG类型 #ifndef _IP_LOCATOR_H_ #define _IP_LOCATOR_H_ #include <string> #include <iostream> #include <fstream> using std::string; using std::streamsize; class IPLocator { public: IPLocator(const string& ipdb_name); ~IPLocator(); string getVersion(); string getIpAddr(const string& ip); string getIpRange(const string& ip); unsigned int getTotal(); private: string getIpAddr(unsigned int ip); string getIpRange(unsigned int ip); static unsigned int getIpFromString(const string& ip); static string getIpString(unsigned int ip); static unsigned int bytes2integer(unsigned char *ip, int count); void readFromFile(streamsize offset, unsigned char *buf,int len); string readStringFromFile(streamsize offset); string getAddr(streamsize offset); string getAreaAddr(streamsize offset); void setIpRange(unsigned int rec_no); private: std::ifstream ipdb; unsigned int first_index; unsigned int last_index; unsigned int index_count; unsigned int cur_start_ip; unsigned int cur_start_ip_offset; unsigned int cur_end_ip; }; #endif
写Android.mk文件:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #添加log模块 LOCAL_LDLIBS+= -llog LOCAL_MODULE := qqand LOCAL_SRC_FILES := qqand.cpp \ IPLocator.cpp include $(BUILD_SHARED_LIBRARY)
写Android.mk文件
#使用gnu标准函数库 APP_STL := gnustl_static #APP_ABI := armeabi armeabi-v7a x86
编译成功,就可以使用了,完善java的接口类:
package com.hu.qqwryand; import java.io.UnsupportedEncodingException; /** * QQwry jni 接口类 * @author Administrator * */ public class QQWryAnd { public QQWryAnd(String datPath) { this.jniOpen(datPath); } /** * * @return 获取版本信息 */ public String getVersion() { return getStr(jniGetVersionBytes()); } /** * * @param ip String类型IP地址 * @return Ip归属地信息 */ public String getIpAddr(String ip) { return getStr(jniGetIpAddrBytes(ip)); } /** * * @param ip IP地址 * @return Ip地址范围 */ public String getIpRange(String ip) { return getStr(jniGetIpRangeBytes(ip)); } /** * * @return IP数据库总地址条数 */ public int getIpCount(){ return jniGetIpCount(); } public void close() { this.jniClose(); } private String getStr(byte[] array){ //将byte数组按GBK方式转换成String String str = ""; try { str = new String(array, "GBK"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return str; } private native void jniOpen(String datPath); private native byte[] jniGetVersionBytes(); private native byte[] jniGetIpAddrBytes(String ip); private native byte[] jniGetIpRangeBytes(String ip); private native int jniGetIpCount(); private native void jniClose(); /** * 加载动态库 */ static { System.loadLibrary("qqand"); } }
这样上层的接口也完成了,只需要在Activity中调用就行了。
其他还有一些文件操作:
最后的效果:
完
相关推荐
Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例
Android开发手记一_NDK编程实例Android开发手记一_NDK编程实例Android开发手记一_NDK编程实例
Android NDK入门 实例 详解
android ndk 开发入门小例子。 博客地址http://blog.csdn.net/u014702653/article/details/51861013
基于NDK TOOL的动态库实现,包含JNI调用、动态库的编译。 1、编译本地调用的JAVA类 2、使用javah从JAVA类中转换成相应的头文件(已有genHeader.bat的脚本直接生成,其中的com.ex.sot.NativeDataManage是相应的类,需...
使用Android NDK编译Android平台的eXosip库,有静态库和动态库。
Android NDK 绘图实例,从网上碰到的一个例子,在这里分享下,同时自己做个资源保存
android NDK访问实例成员变量
Android NDK 开发实例大全 NDK开发所以步骤详细介绍
android ndk,双libs打包实例
这是一个ndk入门实例,使用eclipse实现的,很简单且具有参考意义 参考黄书《Android应用安全防护和逆向分析》第二章Android NDK开发2.1.1节以及百度经验 Android NDK入门开发实例...
简单明了的android ndk 开发实例,没有 过多的解释,其实也不用太多解释,本文所举例子比hellojni 稍微复杂那么一点点。
需要在系统源码下编译,或者提取出对应的头文件亦可。这里需要注意Android4.x以后系统SeLinux如果打开,系统级需要配置对应的sepolicy才能使用。测试阶段推荐直接setenforce 0关闭鉴权即可
不管你是想将已经存在的原生代码应用移植到Android平台上还是准备开始在Android平台上进行软件开发,使用《Android C++高级编程——使用NDK》一书提供的技术可以构建更出色的应用。本书将展示构建性能更好的复杂原生...
《Android C++高级编程——使用NDK》提供了Java原生接口(JNI)的概述、Bionic API、POSIX 线程和套接字、C++支持、原生图形和声音API以及NEON/SIMD优化,在一个游戏应用案例的帮助下,你将学到很多关键技能。...
android ndk开发实例,非常好的了解ndk的教程,不用java代码写出activity
博客名称 : 【Android NDK 开发】在 C 代码中获取 Android 系统信息 ( NDK 项目创建 | NDK 配置 | 获取 Android 系统版本号 ) 博客地址 : https://hanshuliang.blog.csdn.net/article/details/102933704
一个Android Studio实现NDK调用的demo,快速入门NDK 一个Android Studio实现NDK调用的demo,快速入门NDK 一个Android Studio实现NDK调用的demo,快速入门NDK
一个简单的NDK开发实例,实现了android应用对c语言静态库的调用。