android开发分享实例详解Android中JNI的使用方法

目录1.导入c语言的类2.接着导入android.mk文件6.将生成的so文件拷入src/main/jnilibs中7.调用c语言方法的activity如下前言做android开发的程序员应该都知道,

目录
  • 1.导入c语言的类
  • 2.接着导入android.mk文件
  • 6.将生成的so文件拷入src/main/jnilibs中
  • 7.调用c语言方法的activity如下

前言

做android开发的程序员应该都知道,android的开发语言我们都是在使用java(kotlin和flutter我们暂时不考虑)。但是,有时候我们也需要使用到c语言进行一些功能的开发。这个时候我们就需要用到jni了。

1.导入c语言的类

首先我们需要把c语言写的功能类放入我们的项目中。这里我直接从资料中找了一个,毕竟我不会写。路径在src/main/jni中

find_name.cpp

  #include <jni.h>  #include <string.h>     #include <stdio.h>  #include <stdlib.h>  #include <string.h>  #include <netdb.h>  #include <sys/stat.h>  #include <sys/types.h>  #include <sys/select.h>  #include <sys/socket.h>  #include <netinet/in.h>  #include <arpa/inet.h>     #define send_maxsize 50  #define recv_maxsize 1024     struct netbiosns {  	unsigned short int tid; //unsigned short int 占2字节  	unsigned short int flags;  	unsigned short int questions;  	unsigned short int answerrrs;  	unsigned short int authorityrrs;  	unsigned short int additionalrrs;  	unsigned char name[34];  	unsigned short int type;  	unsigned short int classe;  };     char *getnamefromip(const char *ip);     extern "c"     jstring java_com_hao_cmake_mainactivity_cpufromjni(jnienv* env, jobject thiz, jstring ip) {  	const char* str_ip;  	str_ip = env->getstringutfchars(ip, 0);  	return env->newstringutf(getnamefromip(str_ip));  }     char *getnamefromip(const char *ip) {  	char str_info[1024] = { 0 };  	struct sockaddr_in toaddr; //sendto中使用的对方地址  	struct sockaddr_in fromaddr; //在recvfrom中使用的对方主机地址  	char send_buff[send_maxsize];  	char recv_buff[recv_maxsize];  	memset(send_buff, 0, sizeof(send_buff));  	memset(recv_buff, 0, sizeof(recv_buff));  	int sockfd; //socket  	unsigned int udp_port = 137;  	int inetat;  	if ((inetat = inet_aton(ip, &toaddr.sin_addr)) == 0) {  		sprintf(str_info, "[%s] is not a valid ip addressn", ip);  		return str_info;  	}  	if ((sockfd = socket(af_inet, sock_dgram, ipproto_udp)) < 0) {  		sprintf(str_info, "%s socket error sockfd=%d, inetat=%dn", ip, sockfd, inetat);  		return str_info;  	}  	bzero((char*) &toaddr, sizeof(toaddr));  	toaddr.sin_family = af_inet;  	toaddr.sin_addr.s_addr = inet_addr(ip);  	toaddr.sin_port = htons(udp_port);     	//构造netbios结构包  	struct netbiosns nbns;  	nbns.tid = 0x0000;  	nbns.flags = 0x0000;  	nbns.questions = 0x0100;  	nbns.answerrrs = 0x0000;  	nbns.authorityrrs = 0x0000;  	nbns.additionalrrs = 0x0000;  	nbns.name[0] = 0x20;  	nbns.name[1] = 0x43;  	nbns.name[2] = 0x4b;  	int j = 0;  	for (j = 3; j < 34; j++) {  		nbns.name[j] = 0x41;  	}  	nbns.name[33] = 0x00;  	nbns.type = 0x2100;  	nbns.classe = 0x0100;  	memcpy(send_buff, &nbns, sizeof(nbns));  	int send_num = 0;  	send_num = sendto(sockfd, send_buff, sizeof(send_buff), 0,  			(struct sockaddr *) &toaddr, sizeof(toaddr));  	if (send_num != sizeof(send_buff)) {  		sprintf(str_info,  				"%s sendto() error sockfd=%d, send_num=%d, sizeof(send_buff)=%dn",  				ip, sockfd, send_num, sizeof(send_buff));  		shutdown(sockfd, 2);  		return str_info;  	}  	int recv_num = recvfrom(sockfd, recv_buff, sizeof(recv_buff), 0,  			(struct sockaddr *) null, (socklen_t*) null);  	if (recv_num < 56) {  		sprintf(str_info, "%s recvfrom() error sockfd=%d, recv_num=%dn", ip,  				sockfd, recv_num);  		shutdown(sockfd, 2);  		return str_info;  	}  	//这里要初始化。因为发现linux和模拟器都没问题,真机上该变量若不初始化,其值就不可预知  	unsigned short int numberofnames = 0;  	memcpy(&numberofnames, recv_buff + 56, 1);  	char str_name[1024] = { 0 };  	unsigned short int mac[6] = { 0 };  	int i = 0;  	for (i = 0; i < numberofnames; i++) {  		char netbiosname[16];  		memcpy(netbiosname, recv_buff + 57 + i * 18, 16);  		//依次读取netbios name  		if (i == 0) {  			sprintf(str_name, "%s", netbiosname);  		}  	}  	sprintf(str_info, "%s|%s|", ip, str_name);  	for (i = 0; i < 6; i++) {  		memcpy(&mac[i], recv_buff + 57 + numberofnames * 18 + i, 1);  		sprintf(str_info, "%s%02x", str_info, mac[i]);  		if (i != 5) {  			sprintf(str_info, "%s-", str_info);  		}  	}  	return str_info;  }

这里要注意一点,jstring java_com_hao_cmake_mainactivity_cpufromjni方法中,com_hao_cmake是我们的包名,mainactivity是调用jni的activity名称,cpufromjni是对应方法的免费精选名字大全。

2.接着导入android.mk文件

这个文件也是放在jni文件夹中

  local_path := $(call my-dir)  include $(clear_vars)     # 指定so库文件的名称  local_module    := jni_mix  # 指定需要编译的源文件列表  local_src_files := find_name.cpp  # 指定c++的编译标志  local_cppflags += -fexceptions  # 指定要加载的静态库  #local_whole_static_libraries += android_support  # 指定需要链接的库  local_ldlibs    := -llog     include $(build_shared_library)  $(call import-module, android/support)

3.我们配置一下build.gradle文件

android  ->  defaultconfig 下添加

  externalnativebuild{      ndkbuild{          abifilters "arm64-v8a","armeabi-v7a"      }  }

android 下添加

  externalnativebuild {      ndkbuild {          path file('src/main/jni/android.mk')      }  }  packagingoptions{      pickfirst 'lib/arm64-v8a/libjni_mix.so'      pickfirst 'lib/armeabi-v7a/libjni_mix.so'  }

4.好了,此时可以编译一下项目了

5.此时我们可以找一下我们生成的so包了

在build → intermediates → ndkbuild → debug → obj → local下,我们可以找到我们生成的相关配置平台的so文件

6.将生成的so文件拷入src/main/jnilibs中

这个样子的

实例详解Android中JNI的使用方法

7.调用c语言方法的activity如下

  public class mainactivity extends appcompatactivity {         public native string cpufromjni(string ip);         static {          system.loadlibrary("jni_mix");      }         @override      protected void oncreate(bundle savedinstancestate) {          super.oncreate(savedinstancestate);          setcontentview(r.layout.activity_main);          string str = cpufromjni("192.168.0.163");          toast.maketext(this,str,toast.length_short).show();      }  }

这样我们就完成了用c语言类生成so包,并使用jni进行调用的全流程。

注意:在使用jni进行调用的时候,我们的环境一定要有ndk,这个我这里就不说了,大家如果没有搭建需要上网找找搭建一下。

总结

到此这篇关于android中jni使用的文章就介绍到这了,更多相关android中jni使用内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/889114.html

(0)
上一篇 2021年10月19日
下一篇 2021年10月19日

精彩推荐