学习做一个使用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中,...
Android NDK(Native Development Kit)是Google提供的一个工具集,使得开发者能够在Android应用中使用原生代码,以提高性能、处理底层硬件或者利用已有的C/C++库。本实例“Android NDK实例demo”将向我们展示如何...
Android NDK(Native Development Kit)是Google为Android平台提供的一个工具集,允许开发者使用C/C++等原生代码编写部分应用程序,从而实现高性能计算、图形处理或者利用已有的C/C++库。本教程将深入浅出地介绍...
### Android NDK-Stack 使用说明 #### 一、概述 在使用Cocos2d-x、JNI及Android NDK进行开发时,经常会遇到调试困难的问题。尤其是对于C/C++代码的调试,由于涉及到本地代码与Java层之间的交互,使得调试过程变得...
Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的C和C++库开发工具集。这个“android-ndk-r23b-linux.zip”文件是NDK的一个特定版本,即r23b,专为Linux操作系统设计。在Android...
NDK是Android应用开发中的一个重要组成部分,它允许开发者使用原生代码(如C、C++)来编写部分应用程序,从而利用底层的硬件性能,提高程序运行效率,尤其是在处理图形计算、物理模拟和游戏引擎等高性能需求的场景下...
本文将深入探讨如何使用Android NDK(Native Development Kit)来编译适用于Android平台的eXosip库,包括静态库和动态库的构建过程。 首先,eXosip是基于OSI(Open Systems Interconnection)模型的SIP协议栈,它是...
Android NDK(Native Development Kit)是Google为Android平台提供的一套工具,允许开发者使用C、C++等原生代码编写应用程序。它与Android SDK结合,提供了在Android应用中使用原生代码的能力,这对于处理高性能计算...
### 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是Android开发中的重要组成部分,尤其对于需要高性能计算或者复用C/C++代码的应用场景,它的使用能够极大地提升开发效率和应用性能。然而,使用NDK也需要开发者具备C/C++编程基础,以及对JNI和...
NDK的主要功能是让开发者能够在Android应用中使用原生代码,例如C、C++,以实现高性能计算或利用硬件加速等功能。 **JNI(Java Native Interface)**是Android NDK的核心组成部分,它提供了Java和本地代码之间的...
这个工具允许开发者在Android应用中使用原生代码,以实现高性能计算、图形处理、游戏引擎等复杂功能。`android-ndk-r25b-darwin.zip` 是针对macOS系统的NDK版本,版本号为r25b,包含了一系列用于构建、编译和调试...
### Android开发手记一_NDK编程实例 #### 一、开发环境的搭建 在开始具体的NDK编程之前,首先需要确保开发环境已经被正确地搭建起来。对于初次接触Android NDK开发的朋友来说,拥有一个良好的环境配置是至关重要的...
Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的开发工具,它允许开发者使用C++和其他原生编程语言编写应用的部分或全部代码。这个“android-ndk-r26b-linux.zip”文件是NDK的一个...
NDK允许开发者在Android应用中使用原生代码,以实现高性能、低级别的硬件交互以及利用已有的C/C++库。在本案例中,我们关注的是"android-ndk-r26b-darwin.zip",这是一个专为macOS系统设计的NDK版本。 **Android ...