这篇文章是上一篇使用rust写安卓库的续篇,本身按照上一篇文章的介绍已经完全基本讲清楚了使用rust给安卓写库的基本方面,这篇文章继续在之前的状态上补充,力求文章完备。
本文要解决的场景如下
当我们外部调用rust库时难免出现库本身状态出现问题,比如内部错误,比如参数错误。假如我们在只使用同一种语言,这种问题很好处理,善用语言错误处理机制即可。然而我们跨语言就出现了问题,如在之前文章设定的场景:java端的错误是Exception,rust端的错误是Result和Option。
所以我们采用状态码来传递错误信息。着重于传递错误信息。我们把想传递的消息给调用端即可。毕竟作为库的使用者,并不知道库内部的具体信息,只需要知道我作为传递信息者有什么问题就好了。库的问题由库来解决。
在设定以上场景之后,我们的问题就很容易解决。除去错误处理这个杂质,进一步简化问题为如下
调用端传递信息进库,库返回状态(对象)给的调用者。
唯一的问题就是跨语言。(这个属于具体使用rust-jni库的细节,如果要写一个跨语言的库,大体是这种处理方案)
然后我们来写代码(设定场景,java调用rust库。)
首先在java端定义错误本身
1 | class JniApi { |
注意,以上的代码并不符合java规范。只是可用。如果规范,请给StatusMessage实现toString()方法。本文为了简化,没有写。
StatusMessage定义了消息本身,它很简单,一个状态码和一个状态消息。定义静态方法,返回StatusMessage本身。然后在main中调用静态方法。最后打印返回的StatusMessage对象。
接下来在rust端实现send_message方法本身
1 |
|
对上面代码做简单说明。
首先,rust方法的命名来自于对java文件得到javac -h 操作。这个上一篇文章提到过。JNIEnv和JClass这两个是固定的参数,第三个参数是JString对应,静态方法中传入的字符串型参数。
代码得到正文是获取输入参数,他的使用方法是固定的,使用env参数获取
接下来我们填充需要返回的StatusMessage,所有的java class在rust端都被jni-rs抽象为jobject。
第一步,我们寻找class。我们使用env.fin_class()方法完成这一点。其中的参数代表类的名字。如果熟悉java,我们知道JniApi$StatusMessage,这种写法代表内部类。在javac -h生成的文件中我们也可以发现这一点。
第二步,分配内存。我们使用env.alloc_object()来实现
第三步,填充field。因为在java,我们把class持有的数据称为filed。具体参数请查看jni-rs的文档。单独提出来两点,对于int,我们理解为JValue::Int,对于的对象类型(java端的String)我们使用了JValue::Object。他们属于jni-rs使用的细节。
最后返回jobject对象即可
最后在总结成四个步骤
- 定位class
- 分配内存
- 填充field
- 返回jobject
以上已经完全说清楚如何返回给使用端一个java可以理解的”对象“。更复杂的情况也是以上四步大象装进冰箱法。当然其实这些都属于jni-rs的使用细节,我只是单独把它拿出来讲。
希望通过这两篇文章把如何使用rust给安卓写动态库的问题讲清楚。前一篇种配置和基本思路,这篇讲具体细节。