djinni使用实践(三)--Android项目中的使用

djinni使用实践(一) -- 官方文档

djinni使用实践(二) -- djinni究竟都有哪些配置选项

djinni使用实践(三)--Android项目中的使用

       本篇是介绍djinni在Android项目中JNI开发的使用场景,所以默认大家有一定的Android JNI开发经验,此篇中涉及到的JNI相关的知识点不做介绍,大家可自行学习。

       djinni工具集成过程中需要用到该项目中的一些文件,我们先下载到本地以备使用

djinni项目地址

接下来先看下工程结构:

着重看下djinni相关的文件夹: api_generator

ok,工程整体结构大概就是这个样子,关于目录层级及目录名称大家可以按需调整。

         接下来是构建整个项目中的第一个操作:根据djinni文件自动生成接口文件和bean文件,为了方便项目自动化构建我们将所有的要执行的命令行写成脚本文件。

info.djinni

//枚举
sex_mode_enum = enum {
	SEX_MAN;
	SEX_WOMAN;
}


//数据结构(java中的bean对象,c中的结构体)
test_info_store = record {
    id: i32;
	name: string;
	project: string;
	sex: sex_mode_enum;
}

//接口类
test_djnni_interface = interface +c {
	show(testInfo: test_info_store): string;
	static newInstance(): test_djnni_interface;
	const version: i32 = 1;
}

djinni文件编写可参考本系列第一篇文章。

generate.sh

#!/bin/bash

#返回这个脚本文件放置的目录
cd `dirname $0`

rm -rf ../auto_gen/*

djinniFile(){
	java -jar ./djinni.jar \
	     --idl ../api_idl/$1\
	     \
	     --cpp-namespace test::hello \
	     --cpp-out ../auto_gen/cpp_impl/ \
	     --cpp-header-out ../auto_gen/public/include/$2 \
	     --hpp-ext h \
	     --ident-cpp-enum FOO_BAR \
	     --ident-cpp-method FooBar \
	     \
	     --java-out ../auto_gen/java/$2/ \
	     --java-package com.zhoumohan.djinni.gen \
	     --java-use-final-for-record true \
	     --jni-out ../auto_gen/jni/$2 \
	     --ident-jni-class JNIFooBar \
	     --ident-jni-file JNIFooBar \
	     --java-implement-android-os-parcelable false \
	     \
	     --objc-out ../auto_gen/objc/$2 \
	     --objcpp-out ../auto_gen/objc-cpp/$2 \
	     --objc-swift-bridging-header "test-hello-Bridging-Header"

}

//调用djinniFile这个函数,后面为两个参数,对应函数中的$1、$2变量
djinniFile info.djinni "common"

关于脚本文件如何编写,可以参考本系列的文章的第二篇。

执行generate.sh  shell脚本文件,没有报错的话,此时auto_gen文件夹及子文件已经成功生成了。

不难看出其中的对应关系。

然后我们来实现自动生成的c++接口,这样我们就能在java层调用c层的方法实现了。

test_djinni_wrapper.cpp

接下来第二步就是把生成的文件放到android工程里,进行混合编译,为了自动化编译我们也写了一个脚本来做文件的映射(软连接)。

build_android.sh

#!/bin/bash

cd `dirname $0`
work_dir=$(pwd)

#配置ndk环境变量,将ndk的path赋值给ANDROID_NDK_ROOT
if [ $ANDROID_NDK_HOME ];then
  ANDROID_NDK_ROOT=$ANDROID_NDK_HOME
fi

echo $ANDROID_NDK_ROOT

function clean(){
  echo "clean"
	rm -rf CMakeCache.txt
	rm -rf CMakeFiles
	rm -rf cmake_install.cmake
	rm -rf Makefile
}

function unln_source_files {
	echo "unln_source_files"
	cd ..
	base_path=$(pwd)
  library_path=${base_path}/android_files/sample

  dest_support="${library_path}/app/src/main/cpp/support_lib"
  unlink ${dest_support}

  dest_jni="${library_path}/app/src/main/cpp/jni"
  for f in $(find $dest_jni -type l); do rm -rf $f; done

  dest_header="${library_path}/app/src/main/cpp/header"
  for f in $(find $dest_header -type l); do rm -rf $f; done

  dest_src="${library_path}/app/src/main/cpp/common_src"
  for f in $(find $dest_src -type l); do rm -rf $f; done

  dest_java="${library_path}/app/src/main/java/com/zhoumohan/djinni/gen"
  for f in $(find $dest_java -type l); do rm -rf $f; done

  dest_third="${library_path}/app/src/main/cpp/third_part"
  unlink ${dest_third}
}

function ln_source_files {
	echo "ln_source_files"

	base_path=$(pwd)
	library_path=${base_path}/android_files/sample

  # djinni库相关文件软链接
	source_support="${base_path}/api_generator/support_lib"
	dest_support="${library_path}/app/src/main/cpp/support_lib"
	ln -snf $source_support $dest_support

	# djinni生成的JNI接口文件的软链接
	source_jni="${base_path}/api_generator/auto_gen/jni/common/*"
	dest_jni="${library_path}/app/src/main/cpp/jni"
	
	# djinni生成C++头文件的软链接
	source_header="${base_path}/api_generator/auto_gen/public/include/common/*"
  dest_header="${library_path}/app/src/main/cpp/header"
    
  # 自己写的C++文件的软链接
  source_src="${base_path}/src/common/*"
  dest_src="${library_path}/app/src/main/cpp/common_src"

  # 生成的java文件的软链接
  source_java="${base_path}/api_generator/auto_gen/java/common/*"
  dest_java="${library_path}/app/src/main/java/com/zhoumohan/djinni/gen"


  # 第三方库(c++)的软链接
  source_third="${base_path}/third_part"
  dest_third="${library_path}/app/src/main/cpp/third_part"
  ln -snf $source_third $dest_third

  mkdir -p $dest_jni
  mkdir -p $dest_header
  mkdir -p $dest_src
  mkdir -p $dest_java

  ln -snf $source_jni $dest_jni
  ln -snf $source_header $dest_header
  ln -snf $source_src $dest_src
  ln -snf $source_java $dest_java
}

function build_android() {
  echo "build_android"
  pwd

  cd "android_files/sample/app/src/main/cpp"

  cmake . \
      -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake \
      -DCMAKE_SYSTEM_NAME=Android \
      -DANDROID_NDK=$ANDROID_NDK_ROOT \
      -DANDROID_ARM_NEON=ON \
      -DANDROID_PLATFORM=android-14 \
      -DANDROID_STL=c++_shared \
      -DANDROID_TOOLCHAIN=clang \
      -DCMAKE_BUILD_TYPE=Release \
      -DANDROID_ABI=armeabi-v7a

  make -j4
  clean
}


unln_source_files
ln_source_files
build_android

cd $work_dir



不过在执行此脚本之前配置你的sdk路径,及CMakeLists.txt的编写

CMakeLists.txt


#设置工程名
project("mytest")
#设置最低版本
cmake_minimum_required(VERSION 3.6.0)

#给变量赋值,设置编译参数,指定c++标椎库
#set(CMAKE_C_FLAGS_RELEASE "-std=c++11 -O2 -s ")
set(CMAKE_CXX_FLAGS_RELEASE "-std=c++11 -O2 ")
#set(CMAKE_C_FLAGS_DEBUG "-std=c++11 -O2 ")
set(CMAKE_CXX_FLAGS_DEBUG "-std=c++11 -O2 ")


set(COMMON_SRC_ROOT "./common_src/")
#加载以下路径中的所有文件
file(GLOB all_src
        "${COMMON_SRC_ROOT}/*.hpp"
        "${COMMON_SRC_ROOT}/*.cpp"
        )

#构建一个库供他人使用(库名称(name) 库类型 源文件),
#用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为 name
add_library(mytest SHARED
        ${all_src})

file(GLOB jni_src
        "${CMAKE_CURRENT_SOURCE_DIR}/jni/*.h"
        "${CMAKE_CURRENT_SOURCE_DIR}/jni/*.cpp"
        )
#向test库添加源文件
target_sources(mytest PRIVATE ${jni_src})

#添加头文件
target_include_directories(mytest PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/header
        )

#添加头文件
target_include_directories(mytest PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/support_lib/include/jni
        ${CMAKE_CURRENT_SOURCE_DIR}/support_lib/include
        )

file(GLOB support_src
        "${CMAKE_CURRENT_SOURCE_DIR}/support_lib/*.cpp"
        )
target_sources(mytest PRIVATE ${support_src})

set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../..)
if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
    set_target_properties(mytest
            PROPERTIES
            ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_ROOT}/android_files/android_out/${CMAKE_ANDROID_ARCH_ABI}"
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_ROOT}/android_files/android_out/${CMAKE_ANDROID_ARCH_ABI}")
elseif (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
    set_target_properties(mytest
            PROPERTIES
            ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_ROOT}/android_files/android_out/${CMAKE_ANDROID_ARCH_ABI}/Debug"
            LIBRARY_OUTPUT_DIRECTORY "${PROJECT_ROOT}/android_files/android_out/${CMAKE_ANDROID_ARCH_ABI}/Debug")
endif()


find_library( log-lib
              log )

target_link_libraries( mytest
                       ${log-lib} )

大家可根据自己项目修改配置文件。

最后附上github地址,方便大家参考。djinniDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Djinni ,可以使用 `std::string` 的构造函数来把 `std::vector<uint8_t>` 转换为 `std::string`。例如: ```cpp std::vector<uint8_t> buffer = …; std::string str(buffer.begin(), buffer.end()); ``` 注意,这种方法只适用于转换包含 ASCII 字符的 buffer,如果 buffer 包含非 ASCII 字符,则会出现乱码。如果需要转换含有非 ASCII 字符的 buffer,则需要使用适当的字符编码,例如 UTF-8。可以使用以下代码来转换包含 UTF-8 编码的 buffer: ```cpp std::vector<uint8_t> buffer = …; std::string str(buffer.begin(), buffer.end()); std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; std::wstring wide_str = converter.from_bytes(str); std::string utf8_str(wide_str.begin(), wide_str.end()); ``` 这里假设 buffer 的字符均为 UTF-8 编码。如果 buffer 使用了其他字符编码,则需要使用对应的转换器来完成转换。 ### 回答2: 在Djinni,将缓冲区转换为字符串的过程分为两个步骤。首先,通过将缓冲区的内容复制到一个临时`std::string`对象来读取缓冲区的内容。然后,使用Djinni提供的转换函数将临时字符串转换为可在不同编程语言间传递的字符串类型。 为了将缓冲区转换为字符串,我们可以使用以下示例代码: ```cpp // 将缓冲区转换为字符串 std::string bufferToString(const djinni::ByteBuffer& buffer) { // 通过将缓冲区的内容复制到一个临时std::string对象,读取缓冲区的内容 std::string tempString(buffer.begin(), buffer.end()); // 使用Djinni提供的转换函数将临时字符串转换为可传递给不同编程语言的字符串类型 djinni::String convertedString = djinni::String::fromCpp(tempString); // 返回转换后的字符串 return convertedString; } ``` 在这个函数,我们首先将缓冲区的内容复制到一个临时`std::string`对象,通过使用`buffer.begin()`和`buffer.end()`迭代器将缓冲区的开始和结束位置传递给构造函数。然后,我们使用Djinni提供的`fromCpp()`函数将临时字符串转换为可传递给其他编程语言的字符串类型。最后,我们将转换后的字符串返回。 以上是在Djinni将缓冲区转换为字符串的简单示例。请注意,实际实现可能会依赖于具体的编程语言和使用的编译器/工具链。 ### 回答3: 在Djinni,将buffer转换为string的过程如下所示: 1. 首先,需要根据不同的编程语言选择适当的方法。Djinni支持不同的编程语言,如C++、Java和Objective-C等。 2. 如果在C++使用Djinni,可以使用std::string类来表示字符串。可以通过将buffer的数据逐字节复制到std::string对象来完成转换。 3. 如果在Java使用Djinni,可以使用java.nio.charset包的Charset和CharsetDecoder类来实现转换。首先,需要确定使用哪种字符编码。然后,可以通过创建ByteBuffer对象,将buffer的数据写入其,并通过CharsetDecoder对象将其解码为字符串。 4. 如果在Objective-C使用Djinni,可以使用NSString类来表示字符串。可以通过将buffer的数据转换为NSData对象,然后使用NSString的initWithData:encoding:方法将其解码为字符串。 需要注意的是,要正确转换buffer为string,必须确保buffer的数据编码方式与字符串需要的编码方式一致。否则,可能会导致乱码或转换错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值