我试图使用SWIG,以便在Android上使用Spotify API(libspotify):https://developer.spotify.com/technologies/libspotify/
我在定义SWIG接口文件以成功调用以下本机C函数时遇到问题:
sp_error sp_session_create(const sp_session_config * config, sp_session ** sess);
在C语言中被称为:
//config struct defined previously
sp_session *sess;
sp_session_create(&config, &sess);
但在Java中,我需要这样称呼它:
//config object defined previously
sp_session javaSess = new sp_session();
sp_session_create(config, javaSess);
sp_会话是一个不透明的结构,仅在libspotify的API中定义。h文件格式为:
typedef struct sp_session sp_session;
我期待libspotify库创建它,并给我一个参考。那时我唯一需要的就是将该引用传递给API中的其他函数。
我相信答案就在SWIG界面和打字地图中,但我一直没有成功地尝试应用我在留档中找到的示例。
您应该将您的typedef
声明告知swig。为了做到这一点,您应该使用以下工具编辑界面文件:
typedef struct sp_session sp_session;
但是要注意在SWIG看到任何sp_session之前通知你的typedef(我的意思是在包括API. h之前)。我在typedef识别方面也遇到了同样的问题。也许这个链接会有所帮助。
在最基本的层面上,您可以使用cpointer编写代码。我是SWIG库的一部分,允许在Java中创建直接的“指针指向指针”对象。
例如,给定头文件:
#include <stdlib.h>
typedef struct sp_session sp_session;
typedef struct {} sp_session_config;
typedef int sp_error;
inline sp_error sp_session_create(const sp_session_config *config, sp_session **sess) {
// Just for testing, would most likely be internal to the library somewhere
*sess = malloc(1);
(void)config;
return sess != NULL;
}
// Another thing that takes just a pointer
inline void do_something(sp_session *sess) {}
你可以用以下材料包装:
%module spotify
%{
#include "test.h"
%}
%include "test.h"
%include <cpointer.i>
%pointer_functions(sp_session *, SessionHandle)
这样我们就可以写下:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
SWIGTYPE_p_p_sp_session session = spotify.new_SessionHandle();
spotify.sp_session_create(new sp_session_config(), session);
spotify.do_something(spotify.SessionHandle_value(session));
}
}
在Java中。我们使用SessionHandle_value()
来对双指针进行背离,并使用new_SessionHandle()
为我们创建一个双指针对象。(还有其他用于处理双指针对象的函数)。
上面的内容很好用,包装起来也很简单,但对于Java程序员来说,这很难是“直观的”,理想情况下,我们应该在更像Java的东西中公开整个库。
Java程序员希望新的会话句柄对象将从creator函数返回,并使用异常来指示失败。通过稍微更改接口文件,我们可以让SWIG通过一些类型映射和一些谨慎使用%exception
,生成该接口:
%module spotify
%{
#include "test.h"
%}
// 1:
%nodefaultctor sp_session;
%nodefaultdtor sp_session;
struct sp_session {};
// 2:
%typemap(in,numinputs=0) sp_session ** (sp_session *tptr) {
$1 = &tptr;
}
// 3:
%typemap(jstype) sp_error sp_session_create "$typemap(jstype,sp_session*)"
%typemap(jtype) sp_error sp_session_create "$typemap(jtype,sp_session*)"
%typemap(jni) sp_error sp_session_create "$typemap(jni,sp_session*)";
%typemap(javaout) sp_error sp_session_create "$typemap(javaout,sp_session*)";
// 4:
%typemap(out) sp_error sp_session_create ""
%typemap(argout) sp_session ** {
*(sp_session **)&$result = *$1;
}
// 5:
%javaexception("SpotifyException") sp_session_create {
$action
if (!result) {
jclass clazz = JCALL1(FindClass, jenv, "SpotifyException");
JCALL2(ThrowNew, jenv, clazz, "Failure creating session");
return $null;
}
}
%include "test.h"
编号的评论符合以下几点:
>
sp_session
不透明类型映射到“nice”Java类型,但不允许直接在Java中创建/删除该类型。(如果有一个sp_session_destroy
函数,可以安排在Java对象被销毁时自动调用该函数,如果需要的话,可以使用javadestruct类型映射)。伪空定义与%nodefaultctor
和%nodefaultdtor
相结合,可以实现这一点
numinput=0
),然后在接口的生成C部分中提供它的位置
sp_会话
而不是错误代码,我们需要调整从函数返回的类型映射-最简单的方法是将它们替换为如果函数使用$typemap
声明为返回sp_会话
时将使用的类型映射
最后,我们希望将对sp_session_create
的整个调用包含在一些代码中,这些代码将检查实际返回值,并在指示失败时将其映射到Java异常。我也为此手工编写了以下异常类:
public class SpotifyException extends Exception {
public SpotifyException(String reason) {
super(reason);
}
}
完成所有这些工作后,我们现在可以在Java代码中使用它,如下所示:
public class run {
public static void main(String[] argv) throws SpotifyException {
System.loadLibrary("test");
sp_session handle = spotify.sp_session_create(new sp_session_config());
spotify.do_something(handle);
}
}
它比最初的界面简单得多,也更直观,但编写界面更简单。我倾向于使用高级重命名功能使类型名“看起来更像Java”。
问题内容: 我很难理解如何设置已作为指针传递的接口值。我正在努力实现以下目标: 我要做什么才能使程序输出为 编辑:是否有可能使用所有解决方案? 问题答案: 您可以使用来模拟AppEngine数据存储接口。通常,我说的是最小化反射,但是您(以及AppEngine和其他ORM)在这里没有其他很好的选择来展示您想要的接口。对于模仿您的内容: 得到与 获得您想要创建的事物的类型 用它创建 (可选)使用,填
问题内容: 我有以下代码: 我一直期望这样做能够成功,因为MyType实现了MyInterface,但是我得到了: 不能将对象(类型 MyType)用作类型 MyInterface作为AcceptInterface的参数:* MyInterface是指向接口的指针,而不是接口 我尝试做类型断言:object。(MyInterface),但这也不起作用。 我该怎么做? 问题答案: 如错误所示, 不能
问题内容: 在Java中,如果有接口: 然后实现是: 所以我的意思是,如果用户想用构造函数声明实例: 那不可能吗? 问题答案: 那不可能吗? 那就对了。你永远做不到 之后你必须选择一个 类 实现了接口(*) ,如: 为什么? 您可以将接口视为类的属性。比喻是形容词,例如“红色”。例如,创建一个红色的球()或一辆红色的汽车()是很有意义的,但是仅创建“红色”()没有任何意义(“红色代表 什么 ?”)
问题内容: 我知道不可能在接口中定义构造函数。但是我想知道为什么,因为我认为这可能非常有用。 因此,您可以确定为该接口的每种实现定义了类中的某些字段。 例如,考虑以下消息类: 如果为该类定义一个接口,以便我可以有更多实现消息接口的类,则只能定义send方法,而不能定义构造函数。那么,如何确保此类的每个实现都确实有一个接收者集?如果我使用类似的方法,则不能确定是否真的调用了该方法。在构造函数中,我可
问题内容: 关于接口和类,这让我感到困扰。 我正在尝试通过名为IPAddressString的类对名为IPAddress的接口进行实施。Ipadress包含四个部分。 我正在编写一个名为mask的方法,该方法用给定的地址屏蔽当前地址。掩码操作是对地址的所有四个部分进行按位“与”操作。您可以通过我编写的名为getOctet的方法来获得所有四个部分。(您可以在下面看到)。 好的,所以我需要掩盖我的
我从我正在使用的库中收到以下接口: 如何创建该类的实现?(我需要一个测试模拟)一个自然的实现,构造函数定义为: