Djinni_初试IOS

Djinni_IOS初步使用

这里简单介绍一下这个开源项目的作用主要是一个工具,完成对跨平台代码的中间层Bridge的自动生成。看一下项目原文介绍。

Djinni is a tool for generating cross-language type declarations and interface bindings. It’s designed to connect C++ with either Java or Objective-C. Python support is available in an experimental version on the python branch.

  1. 选择这个工具的原因其实很简单,因为前面介绍Android和IOS跨平台时都需要去构造复杂的Bridge层,对开发效率也有影响,而这个工具帮我们将中间层Bridge层都自动生成,只需对需要对具体C++和java层逻辑进行coding,而不必关心其中间时如何进行交互的。
  2. 这个工具需要写对应的IDL(.djinni)文件,然后通过shell脚本进行一些配置,完成代码的自动生成,脚本中可以指定一些自动生成文件的参数,方便快捷。
  3. 此篇作为自己学习djinni的一篇记录,方便今后进行一些回顾,在文章中也有很多不对不足的地方,后面会不断学习修改。
  • Types
  1. 这里介绍下Djinni支持的类型,也是写IDL文件的基础,原文介绍如下
  2. Djinni generates code based on interface definitions in an IDL file. An IDL file can contain three kinds of declarations: enums, records, and interfaces.
  • Enums become C++ enum classes, Java enums, or ObjC NS_ENUMs.

  • Flags become C++ enum classes with convenient bit-oriented operators, Java
    enums with EnumSet, or ObjC NS_OPTIONS.

  • Records are pure-data value objects.

  • Interfaces are objects with defined methods to call (in C++, passed by shared_ptr). Djinni produces code allowing an interface implemented in C++ to be transparently used from ObjC or Java, and vice versa.


  • 1 ——IDL file

(1)此IDL文件为原文介绍,下面为demo的IDL file

my_enum = enum {
    option1;
    option2;
    option3;
}

my_flags = flags {
  flag1;
  flag2;
  flag3;
  no_flags = none;
  all_flags = all;
}

my_record = record {
    id: i32;
    info: string;
    store: set<string>;
    hash: map<string, i32>;

    values: list<another_record>;

    # Comments can also be put here

    # Constants can be included
    const string_const: string = "Constants can be put here";
    const min_value: another_record = {
        key1 = 0,
        key2 = ""
    };
}

another_record = record {
    key1: i32;
    key2: string;
} deriving (eq, ord)

# This interface will be implemented in C++ and can be called from any language.
my_cpp_interface = interface +c {
    method_returning_nothing(value: i32);
    method_returning_some_type(key: string): another_record;
    static get_version(): i32;

    # Interfaces can also have constants
    const version: i32 = 1;
}

# This interface will be implemented in Java and ObjC and can be called from C++.
my_client_interface = interface +j +o {
    log_string(str: string): bool;
}

IDL文件中的类型和C++,OC,Java的类型对照表

  • Boolean (bool)
  • Primitives (i8, i16, i32, i64, f32, f64).
  • Strings (string)
  • Binary (binary). This is implemented as std::vector<uint8_t> in C++, byte[] in Java, and NSData in Objective-C.
  • Date (date). This is chrono::system_clock::time_point in C++, Date in Java, and NSDate in Objective-C.
  • List (list). This is vector in C++, ArrayList in Java, and NSArray in Objective-C. Primitives in a list will be boxed in Java and Objective-C.
  • Set (set). This is unordered_set in C++, HashSet in Java, and NSSet in Objective-C. Primitives in a set will be boxed in Java and Objective-C.
  • Map (map<typeA, typeB>). This is unordered_map<K, V> in C++, HashMap in Java, and NSDictionary in Objective-C. Primitives in a map will be boxed in Java and Objective-C.
  • Enumerations / Flags
  • Optionals (optional). This is std::experimental::optional in C++11, object / boxed primitive reference in Java (which can be null), and object / NSNumber strong reference in Objective-C (which can be nil).
  • Other record types. This is generated with a by-value semantic, i.e. the copy method will deep-copy the contents.

(2) demo.djinni (此文件就是demo中的IDL文件)

#1.  hello_world 是C++对象,+C代表此方法需要在C++层进行实现,然后会自动生成OC和Java层的代码,这样C++实现的API就可以直接被OC和Java层进行调用,是不是很方便呢?
#2.  static 代表C++的静态成员方法,create_with_listener为方法名,()里面是方法的参数,冒号前为参数名,后面为参数类型。()后面冒号为返回值。
#3.  get_hello_world同上

hello_world= interface +c {
        static create_with_listener(listener : text_listener):hello_world;
        get_hello_world(key : string): string;
}


# 此方法为+o +j代表需要在OC和Java层进行实现,C++层通过此对象的完成创建
text_listener = interface +o +j {
        updata_view(key : string) :string;
}

  • 2——Generate Code
  1. 准备好了IDL文件,就可以写shell脚本进行代码的生成了。
  2. 其中sh文件的中一些参数都是见名知意,就不过多介绍了,当然也不仅仅包含这些。

(1) run_djinni.sh文件

#! /usr/bin/env bash

base_dir=$(cd "`dirname "0"`" && pwd)
cpp_out="$base_dir/generated-src/cpp"
jni_out="$base_dir/generated-src/jni"
objc_out="$base_dir/generated-src/objc"
java_out="$base_dir/generated-src/java/com/mycompany/helloworld"
java_package="com.mycompany.helloworld"
namespace="demospace"
objc_prefix="HW"
djinni_file="demo.djinni"

deps/djinni/src/run \
	--java-out $java_out \
	--java-package $java_package \
	--ident-java-field mFooBar \
	\
	--cpp-out $cpp_out \
	--cpp-namespace $namespace \
	\
	--jni-out $jni_out \
	--ident-jni-class NativeFooBar \
	--ident-jni-file NativeFooBar \
	\
	--objc-out $objc_out \
	--objc-type-prefix $objc_prefix \
	\
	--objcpp-out $objc_out \
	\
	--idl $djinni_file

  • 3——执行脚本
  1. sh run_djinni.sh
  2. 你就可以看到genration-src文件了,建议在执行脚本前先新建一个文件夹,将其放入文件夹中。
  3. 对于其他目录,建议在新建文件夹中再见一个src文件夹,用于源代码的coding。
  4. 下图是我在新建的djinni-project目录下tree -L 2
    在这里插入图片描述

  • 4——完成src中源码

src/cpp/hello_world_impl.hpp

#ifndef DJINNI_PROJECT_HELLO_WORLD_IMPL_H
#define DJINNI_PROJECT_HELLO_WORLD_IMPL_H


#include "hello_world.hpp"
#include "text_listener.hpp"

namespace demospace {
    class HelloWorldImpl : public HelloWorld {
    public:
        HelloWorldImpl(const std::shared_ptr <TextListener> listener);

        std::string get_hello_world(const std::string & key);

    private:
        std::shared_ptr <TextListener> _listener;
    };
}// end namespace
#endif //DJINNI_PROJECT_HELLO_WORLD_IMPL_H

src/cpp/hello_world_impl.cpp


#include "hello_world_impl.hpp"

namespace demospace {


    HelloWorldImpl::HelloWorldImpl(const std::shared_ptr <TextListener> listener){
        _listener = listener;
    }

    std::shared_ptr<HelloWorld> HelloWorld::create_with_listener(const std::shared_ptr<TextListener> & listener){
        return std::make_shared<HelloWorldImpl>(listener);
    }

     std::string HelloWorldImpl::get_hello_world(const std::string & key){
         return "getHelloWorld + "+_listener->updata_view(key);
    }


}// end namespace

src/objc/HWTextListenerImpl.h

#import "HWTextListener.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface HWTextListenerImpl : NSObject<HWTextListener>

@end

src/objc/HWTextListenerImpl.m

#include "HWTextListenerImpl.h"

@implementation HWTextListenerImpl

 - (nonnull NSString *)updataView:(nonnull NSString *)key{
    return [NSString stringWithFormat:@"updataView + %@",key];   
}
@end

  • 5——完成内容导入xcode中
  1. 首先新建一个项目HelloWorld
  2. 添加group,分别为djinni,C++,Bridge,OC,其中djinni组为djinni_project/deps/djinni/support-lib/objc,C++为src/cpp,Bridge为generation-src/cpp,OC为src/objc。
  3. 将需要的导入到四个group中,注意是添加reference,而不是copy,否则源文件修改这边感知不到。
  4. 下面是具体操作是的截图
  1. 新建一个HelloWorld项目(省略)
  2. 新建四个group,注意这里建组的时候,只需勾选第三个即可,不要选第一个。

在这里插入图片描述
在这里插入图片描述

  1. 导入需要的文件
    在这里插入图片描述
    之后弹窗记得选择reference,
    在这里插入图片描述
  1. 最后的效果图
    在这里插入图片描述
  1. 以上就是djinni的创建和导入到IOS项目中介绍,这里看官方的是选择建立target而不是group,这里只是为了演示。
  2. GitHub源链接
  3. 官方一些demo
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值