`
hzy3774
  • 浏览: 992347 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

NDK小实例使用QQwry实现Android端IP归属地查询

 
阅读更多

学习做一个使用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中调用就行了。

其他还有一些文件操作:

最后的效果:



 完

  • 大小: 19.7 KB
  • 大小: 15.6 KB
  • 大小: 26 KB
分享到:
评论

相关推荐

    android ndk开发实例代码

    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 JNI 经典实例

    android NDK实现的Hanlder-消息队列-native多线程实例

    本实例关注的是如何在Android NDK环境下实现一个类似Java层的消息队列(Message Queue)和Handler机制,以及如何在原生代码中创建和管理多线程。 首先,我们要理解Java层的Handler和消息队列的工作原理。在Java中,...

    Android NDK实例demo

    Android NDK(Native Development Kit)是Google提供的一个工具集,使得开发者能够在Android应用中使用原生代码,以提高性能、处理底层硬件或者利用已有的C/C++库。本实例“Android NDK实例demo”将向我们展示如何...

    Android NDK入门 实例 详解

    Android NDK(Native Development Kit)是Google为Android平台提供的一个工具集,允许开发者使用C/C++等原生代码编写部分应用程序,从而实现高性能计算、图形处理或者利用已有的C/C++库。本教程将深入浅出地介绍...

    android ndk-stack使用说明。

    ### Android NDK-Stack 使用说明 #### 一、概述 在使用Cocos2d-x、JNI及Android NDK进行开发时,经常会遇到调试困难的问题。尤其是对于C/C++代码的调试,由于涉及到本地代码与Java层之间的交互,使得调试过程变得...

    android-ndk(android-ndk-r23b-linux.zip)

    Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的C和C++库开发工具集。这个“android-ndk-r23b-linux.zip”文件是NDK的一个特定版本,即r23b,专为Linux操作系统设计。在Android...

    android-ndk(android-ndk-r23b-windows.zip)

    NDK是Android应用开发中的一个重要组成部分,它允许开发者使用原生代码(如C、C++)来编写部分应用程序,从而利用底层的硬件性能,提高程序运行效率,尤其是在处理图形计算、物理模拟和游戏引擎等高性能需求的场景下...

    使用Android NDK编译Android平台的eXosip库

    本文将深入探讨如何使用Android NDK(Native Development Kit)来编译适用于Android平台的eXosip库,包括静态库和动态库的构建过程。 首先,eXosip是基于OSI(Open Systems Interconnection)模型的SIP协议栈,它是...

    android ndk 代码实例

    Android NDK(Native Development Kit)是Google为Android平台提供的一套工具,允许开发者使用C、C++等原生代码编写应用程序。它与Android SDK结合,提供了在Android应用中使用原生代码的能力,这对于处理高性能计算...

    android ndk 开发实例

    ### Android NDK 开发实例详解 #### 一、概述 Android NDK (Native Development Kit) 是一套工具集合,允许开发者使用 C 或 C++ 编写应用程序的部分或全部代码。这在需要高性能计算的情况下非常有用,比如游戏开发...

    NDK开发的简单实例(JNI及Android的C组件实现)

    基于NDK TOOL的动态库实现,包含JNI调用、动态库的编译。 1、编译本地调用的JAVA类 2、使用javah从JAVA类中转换成相应的头文件(已有genHeader.bat的脚本直接生成,其中的com.ex.sot.NativeDataManage是相应的类,需...

    android-ndk(android-ndk-r25b-linux.zip)

    总结来说,Android NDK是Android开发中的重要组成部分,尤其对于需要高性能计算或者复用C/C++代码的应用场景,它的使用能够极大地提升开发效率和应用性能。然而,使用NDK也需要开发者具备C/C++编程基础,以及对JNI和...

    android-ndk(android-ndk-r25b-windows.zip)

    NDK的主要功能是让开发者能够在Android应用中使用原生代码,例如C、C++,以实现高性能计算或利用硬件加速等功能。 **JNI(Java Native Interface)**是Android NDK的核心组成部分,它提供了Java和本地代码之间的...

    android-ndk(android-ndk-r25b-darwin.zip)

    这个工具允许开发者在Android应用中使用原生代码,以实现高性能计算、图形处理、游戏引擎等复杂功能。`android-ndk-r25b-darwin.zip` 是针对macOS系统的NDK版本,版本号为r25b,包含了一系列用于构建、编译和调试...

    Android开发手记一_NDK编程实例

    ### Android开发手记一_NDK编程实例 #### 一、开发环境的搭建 在开始具体的NDK编程之前,首先需要确保开发环境已经被正确地搭建起来。对于初次接触Android NDK开发的朋友来说,拥有一个良好的环境配置是至关重要的...

    android-ndk(android-ndk-r26b-linux.zip)

    Android NDK,全称为Native Development Kit,是Google提供的一款用于Android平台的开发工具,它允许开发者使用C++和其他原生编程语言编写应用的部分或全部代码。这个“android-ndk-r26b-linux.zip”文件是NDK的一个...

    android-ndk(android-ndk-r26b-darwin.zip)

    NDK允许开发者在Android应用中使用原生代码,以实现高性能、低级别的硬件交互以及利用已有的C/C++库。在本案例中,我们关注的是"android-ndk-r26b-darwin.zip",这是一个专为macOS系统设计的NDK版本。 **Android ...

Global site tag (gtag.js) - Google Analytics