jni的基本使用方法请看我的另外一篇博客
http://iyenn.com/rec/1806082.htmlhttps://mp.csdn.net/postedit/83825826
总体思路:
- 新建一个my.cpp和my.h文件
- 利用android studio中的cmake工具将my.cpp编译成全架构(armeabi-v7a,arm64-v8a,x86,x86_64)的库文件。编译时很多问题,报错时出现x86或者armeabi都是因为没有对应的架构造成的,我们索性就直接造一个全架构的库。
- 将第2步中生成的库链接到native-lib.so(系统自动生成的库)中
- 运行,看在native-lib.cpp中的函数能否调用my.cpp中的函数
我们从头开始,最好新建立一个文件。
1.建立jni文件
不多说,看http://iyenn.com/rec/1806082.htmlhttps://mp.csdn.net/postedit/83825826
建立好之后先运行app,看能否运行,不能运行就先百度解决,正常运行之后再进行后面的操作
2.新建my.cpp和my.h
1.在Project视图下 app/src/main/cpp 目录下创建my.cpp同时创建头文件my.h
2.在my.cpp写一个函数,并且添加android的日志库,以便知道当前函数是否被正确被调用
my.h如下:
- #ifndef JNITEST2_MY_H
- #define JNITEST2_MY_H
-
-
- //-----------------------------横线里面的内容为新增--------------------------
- #include
- #define LOG "JNILOG"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
- #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
- #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
-
- int my_fun();
- //-------------------------------------------------------------------------
-
- #endif //JNITEST2_MY_H
my.cpp
- #include "my.h"
-
- //-----------------------------横线里面的内容为新增--------------------------
- int my_fun()
- {
- LOGD("android studio jni");
- return 111;
- }
- //-------------------------------------------------------------------------
3.将my.cpp编译成全架构的.so库
1.修改CMakeLists.txt,只新增了两句,原来的不需要改
- cmake_minimum_required(VERSION 3.4.1)
-
- add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
-
- #-----新增--------
- add_library(my-lib SHARED src/main/cpp/my.cpp)
-
- find_library(log-lib log)
-
- target_link_libraries(native-lib ${log-lib})
-
- #-----新增---------------
- target_link_libraries(my-lib ${log-lib})
2.修改app级别下的build.gradle新增一句
3.点击make project
4.编译成功之后,查看生成的库
在Project目录下 app/build/intermediates/cmake/debug/obj/各种架构
libmy-lib.so就是我们需要链接到libnative-lib.so的库
4.将libmy-lib.so链接到native-lib.so
1.修改CMakeLists.txt文件
- cmake_minimum_required(VERSION 3.4.1)
-
- add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
-
- #-----删除--------
- #add_library(my-lib SHARED src/main/cpp/my.cpp)
-
- #-----新增---------
- add_library(apple SHARED IMPORTED)
- #-----新增---------
- set_target_properties(apple PROPERTIES IMPORTED_LOCATION
- ${CMAKE_CURRENT_SOURCE_DIR}/build/intermediates/cmake/debug/obj/${CMAKE_ANDROID_ARCH_ABI}/libmy-lib.so
- )
-
- find_library(log-lib log)
-
- #------修改---------
- target_link_libraries(native-lib apple ${log-lib})
-
- #-----删除---------------
- #target_link_libraries(my-lib ${log-lib})
#删除的就表示不要了,#新增就表示新添加的,#修改就表示在原来的基础上修改
说明一下set_target_properties这里面的参数。
${CMAKE_CURRENT_SOURCE_DIR} 表示app这个文件夹,也可以用别的参数来表示。因为Android studio的版本不同,参数可能回不一样,但是一定要能定位到cmake/debug/obj这个文件夹。可以用ctrl+左键来试一下能否被识别。
${CMAKE_ANDROID_ARCH_ABI}表示系统会根据自己的要求去不同的架构目录下去寻找libmy-lib.so,所以不要指定单独的文件夹
2.在native-lib.cpp中调用我们my.cpp的函数
- #include
- #include
-
- //---------新增
- #include "my.h"
-
- extern "C" JNIEXPORT jstring JNICALL
- Java_com_example_tuweiguang_jnitest2_MainActivity_stringFromJNI(
- JNIEnv *env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
-
- //-----------新增-------------
- int x = 0;
- x = my_fun();
- LOGD("x = %s",x);
- //---------------------------
-
- return env->NewStringUTF(hello.c_str());
- }
5.运行app
点击运行app
成功调用
至此,jni调用第三方库的教程结束。
还有一些其他问题,目前本人也正在学习,希望共勉:
1.如果我们手里只有单一架构的库,任然希望就在这种架构的及其上运行这种单一架构的库
2.如果你有任何问题,也可以留言,一起讨论
今天无意间发现了一个神奇的事件paste
, 下面来介绍一下吧。
为了测试粘贴复制,下面我们先来写一个点击复制的工具函数
js 代码解读复制代码 const clipboard = (text) => {
return new Promise((resolve, reject) => {
// 创建隐藏的 Textarea 标签,并将文本放入其中
let textarea = document.createElement('textarea')
textarea.style.position = 'absolute'
textarea.style.top = '0'
textarea.style.left = '0'
textarea.style.border = 'none'
textarea.style.margin = '0'
textarea.style.padding = '0'
textarea.style.opacity = '0'
textarea.value = text
document.body.appendChild(textarea)
// 复制 Textarea 标签的文本
textarea.select()
document.execCommand('copy')
// 移除 Textarea 标签
document.body.removeChild(textarea)
resolve()
})
}
paste事件:当用户在浏览器用户界面发起“粘贴”操作时,会触发 paste
事件。
这个只会作用于可输入文本的dom元素上。如果都不可输入,那么我们整个页面也是可以触发的。
下面来看一下例子。
html 代码解读复制代码 html>
<html lang="en" contenteditable="false">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div>页面中没有可以可输入文本的dom元素div>
<script>
document.addEventListener("paste", function(e) {
console.log("e", e)
})
script>
body>
html>
下面我们让div变成可以输入文本的dom。
html 代码解读复制代码 html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
div {
width: 300px;
height: 300px;
background: skyblue;
}
style>
head>
<body>
<div contenteditable="true">
我是可输入文本的div
div>
<script>
const div = document.getElementsByTagName("div")[0]
// 这个事件只作用于可编辑的dom元素上。
// 如果元素都没有设置contenteditable="true",那么将作用于整个网页。
div.addEventListener("paste", function(e) {
console.log("e", e)
})
script>
body>
html>
上面可以看出,只有光标聚焦到div元素上时执行粘贴行为时,才会触发paste事件。
开始的时候我只是想获取剪切板中粘贴的图片对象。就像掘金编辑器一样,平常就是在别的地方拷贝图片到文章中。
我们可以这样获取粘贴的图片对象。然后就可以上传到服务器了。
html 代码解读复制代码 html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
div {
width: 300px;
height: 300px;
background: skyblue;
}
style>
head>
<body>
<div contenteditable="true">
我是可输入文本的div
div>
<script>
const div = document.getElementsByTagName("div")[0]
// 这个事件只作用于可编辑的dom元素上。
// 如果元素都没有设置contenteditable="true",那么将作用于整个网页。
div.addEventListener("paste", function(e) {
// 明明打印e.clipboardData.item没有值,但是最后获取getAsFile时,就可以打印出来。
console.log("e:获取文件对象",e.clipboardData.items[0].getAsFile() )
})
script>
body>
html>
那么获取文件对象会了,那么如何获取普通的复制的文本呢?
事件处理程序可以通过调用事件的 clipboardData
属性上的 getData()
访问剪贴板内容。
html 代码解读复制代码html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
div {
width: 300px;
height: 300px;
background: skyblue;
}
style>
head>
<body>
<div contenteditable="true">
我是可输入文本的div
div>
<p>点我复制p>
<script>
const clipboard = (text) => {
return new Promise((resolve, reject) => {
// 创建隐藏的 Textarea 标签,并将文本放入其中
let textarea = document.createElement('textarea')
textarea.style.position = 'absolute'
textarea.style.top = '0'
textarea.style.left = '0'
textarea.style.border = 'none'
textarea.style.margin = '0'
textarea.style.padding = '0'
textarea.style.opacity = '0'
textarea.value = text
document.body.appendChild(textarea)
// 复制 Textarea 标签的文本
textarea.select()
document.execCommand('copy')
// 移除 Textarea 标签
document.body.removeChild(textarea)
resolve()
})
}
const div = document.getElementsByTagName("div")[0]
const p = document.getElementsByTagName("p")[0]
// 这个事件只作用于可编辑的dom元素上。
// 如果元素都没有设置contenteditable="true",那么将作用于整个网页。
div.addEventListener("paste", function(e) {
// 获取剪切板中的文本内容
console.log("e: 获取文本",e.clipboardData.getData("text"))
})
// 点击div复制div中的内容到剪贴板
p.addEventListener("click", function() {clipboard(p.innerText)})
script>
body>
html>
到此就结束啦,如果就得学到啦,就给一个小小的star,谢您们~
评论记录:
回复评论: