学习做一个使用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是一个重要的工具集,它允许开发者在Android应用中使用原生代码,如C++和Fortran,来实现性能敏感或需要底层硬件交互的部分。这个"android ndk开发实例代码"提供了一个入门级的示例,帮助开发者理解NDK和...
Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例Android NDK JNI 经典实例
本实例关注的是如何在Android NDK环境下实现一个类似Java层的消息队列(Message Queue)和Handler机制,以及如何在原生代码中创建和管理多线程。 首先,我们要理解Java层的Handler和消息队列的工作原理。在Java中,...
NDK的主要功能是让开发者能够在Android应用中使用原生代码,例如C、C++,以实现高性能计算或利用硬件加速等功能。 **JNI(Java Native Interface)**是Android NDK的核心组成部分,它提供了Java和本地代码之间的...
Android NDK(Native Development Kit)是Google提供的一个工具集,使得开发者能够在Android应用中使用原生代码,以提高性能、处理底层硬件或者利用已有的C/C++库。本实例“Android NDK实例demo”将向我们展示如何...
Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的C和C++库开发工具集。这个“android-ndk-r23b-linux.zip”文件是NDK的一个特定版本,即r23b,专为Linux操作系统设计。在Android...
Android NDK(Native Development Kit)是Google为Android平台提供的一个工具集,允许开发者使用C/C++等原生代码编写部分应用程序,从而实现高性能计算、图形处理或者利用已有的C/C++库。本教程将深入浅出地介绍...
### Android NDK-Stack 使用说明 #### 一、概述 在使用Cocos2d-x、JNI及Android NDK进行开发时,经常会遇到调试困难的问题。尤其是对于C/C++代码的调试,由于涉及到本地代码与Java层之间的交互,使得调试过程变得...
NDK是Android应用开发中的一个重要组成部分,它允许开发者使用原生代码(如C、C++)来编写部分应用程序,从而利用底层的硬件性能,提高程序运行效率,尤其是在处理图形计算、物理模拟和游戏引擎等高性能需求的场景下...
Android NDK(Native Development Kit)是Google为Android平台提供的一套工具,允许开发者使用C、C++等原生代码编写应用程序。它与Android SDK结合,提供了在Android应用中使用原生代码的能力,这对于处理高性能计算...
总结来说,Android NDK是Android开发中的重要组成部分,尤其对于需要高性能计算或者复用C/C++代码的应用场景,它的使用能够极大地提升开发效率和应用性能。然而,使用NDK也需要开发者具备C/C++编程基础,以及对JNI和...
### Android NDK 开发实例详解 #### 一、概述 Android NDK (Native Development Kit) 是一套工具集合,允许开发者使用 C 或 C++ 编写应用程序的部分或全部代码。这在需要高性能计算的情况下非常有用,比如游戏开发...
基于NDK TOOL的动态库实现,包含JNI调用、动态库的编译。 1、编译本地调用的JAVA类 2、使用javah从JAVA类中转换成相应的头文件(已有genHeader.bat的脚本直接生成,其中的com.ex.sot.NativeDataManage是相应的类,需...
本文将深入探讨如何使用Android NDK(Native Development Kit)来编译适用于Android平台的eXosip库,包括静态库和动态库的构建过程。 首先,eXosip是基于OSI(Open Systems Interconnection)模型的SIP协议栈,它是...
Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的C和C++开发工具集。这个压缩包“android-ndk-r26b-windows.zip”包含了NDK的第26个版本,专为Windows操作系统设计。通过这个工具,...
《Android C++高级编程使用NDK》是一本深入探讨如何在Android平台上利用C++进行高效开发的专业书籍。这本书源码的提供,对于开发者来说是一份宝贵的参考资料,它涵盖了多个章节的示例代码,帮助读者更好地理解和实践...
这个工具允许开发者在Android应用中使用原生代码,以实现高性能计算、图形处理、游戏引擎等复杂功能。`android-ndk-r25b-darwin.zip` 是针对macOS系统的NDK版本,版本号为r25b,包含了一系列用于构建、编译和调试...
Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的开发工具,它允许开发者使用C++和其他原生编程语言编写应用的部分或全部代码。这个“android-ndk-r26b-linux.zip”文件是NDK的一个...
### Android开发手记一_NDK编程实例 #### 一、开发环境的搭建 在开始具体的NDK编程之前,首先需要确保开发环境已经被正确地搭建起来。对于初次接触Android NDK开发的朋友来说,拥有一个良好的环境配置是至关重要的...