【问题标题】:Android JNI bridge Toast C++ not working - How to fix it?Android JNI 桥 Toast C++ 不工作 - 如何解决?
【发布时间】:2015-03-12 17:16:17
【问题描述】:

我正在尝试解决我的 hpp 单元的一个小问题。 我在互联网上找到了一些示例,展示了如何使用 Android JNI 桥接器在屏幕上显示信息,但它只是在 pascal (delphi) 中,所以我决定使用相同的 pas 文件,但使用 hpp 文件进行转换。 到现在我都明白了:

#ifndef Android_Jni_ToastHPP
#define Android_Jni_ToastHPP

#pragma delphiheader begin
#pragma option push
#pragma option -w-                                        // All warnings off
#pragma option -Vx                                        // Zero-length empty class member 
#pragma pack(push,8)
#include <FMX.Helpers.Android.hpp>                        // Pascal unit
#include <Androidapi.JNIBridge.hpp>                       // Pascal unit
#include <Androidapi.JNI.JavaTypes.hpp>                   // Pascal unit
#include <Androidapi.JNI.GraphicsContentViewText.hpp>     // Pascal unit
#include <Androidapi.JNI.Util.hpp>                        // Pascal unit
#include <Androidapi.JNI.App.hpp>                         // Pascal unit
#include <FMX.Surfaces.hpp>                               // Pascal unit

//-- user supplied -----------------------------------------------------------

namespace Android
{
namespace Jni
{
namespace Toast
{
//-- type declarations -------------------------------------------------------

extern DELPHI_PACKAGE Androidapi::Jni::Toast __fastcall Toast(const System::UnicodeString Msg, TToastLength duration);

#pragma pack(pop)

//-- type declarations -------------------------------------------------------
//-- var, const, procedure ---------------------------------------------------

}   /* namespace Android */
}   /* namespace JNI     */
}   /* namespace Toast   */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROID_JNI_TOAST)
using namespace Android::Jni::Toast;
#endif
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROID_JNI)
using namespace Android::Jni;
#endif
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROID)
using namespace Android;
#endif
#pragma pack(pop)
#pragma option pop

#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif  // Androidapi_Jni_ToastHPP

如果你想要帕斯卡单位,这里是:

unit Android.JNI.Toast;

interface

{$IFDEF ANDROID}

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText;
{$ENDIF}
{$IFDEF ANDROID}

type
  TToastLength = (LongToast, ShortToast);

  JToast = interface;

  JToastClass = interface(JObjectClass)
    ['{69E2D233-B9D3-4F3E-B882-474C8E1D50E9}']
    { Property methods }
    function _GetLENGTH_LONG: Integer; cdecl;
    function _GetLENGTH_SHORT: Integer; cdecl;
    { Methods }
    function init(context: JContext): JToast; cdecl; overload;
    function makeText(context: JContext; text: JCharSequence; duration: Integer)
      : JToast; cdecl;
    { Properties }
    property LENGTH_LONG: Integer read _GetLENGTH_LONG;
    property LENGTH_SHORT: Integer read _GetLENGTH_SHORT;
  end;

  [JavaSignature('android/widget/Toast')]
  JToast = interface(JObject)
    ['{FD81CC32-BFBC-4838-8893-9DD01DE47B00}']
    { Methods }
    procedure cancel; cdecl;
    function getDuration: Integer; cdecl;
    function getGravity: Integer; cdecl;
    function getHorizontalMargin: Single; cdecl;
    function getVerticalMargin: Single; cdecl;
    function getView: JView; cdecl;
    function getXOffset: Integer; cdecl;
    function getYOffset: Integer; cdecl;
    procedure setDuration(value: Integer); cdecl;
    procedure setGravity(gravity, xOffset, yOffset: Integer); cdecl;
    procedure setMargin(horizontalMargin, verticalMargin: Single); cdecl;
    procedure setText(s: JCharSequence); cdecl;
    procedure setView(view: JView); cdecl;
    procedure show; cdecl;
  end;

  TJToast = class(TJavaGenericImport<JToastClass, JToast>)
  end;

procedure Toast(const Msg: string; duration: TToastLength = ShortToast);

{$ENDIF}

implementation

{$IFDEF ANDROID}

uses
  FMX.Helpers.Android, Androidapi.Helpers;

procedure Toast(const Msg: string; duration: TToastLength);
var
  ToastLength: Integer;
begin
  if duration = ShortToast then
    ToastLength := TJToast.JavaClass.LENGTH_SHORT
  else
    ToastLength := TJToast.JavaClass.LENGTH_LONG;
  CallInUiThread(
    procedure
    begin
      TJToast.JavaClass.makeText(SharedActivityContext, StrToJCharSequence(Msg),
        ToastLength).show
    end);
end;
{$ENDIF}

end.

但是,使用此源进行编译时出现错误... 我做了什么?

PS.:我到达那个状态只是将 AppMetthod 来源与我正在制作的东西进行比较......

日志:

Checking project dependencies...
Compiling WebBrowser.cbproj (Debug, Android)
bccaarm command line for "uMain.cpp"
  c:\program files (x86)\embarcadero\studio\15.0\bin\bccaarm.exe -cc1 -D _DEBUG -isysroot 
  C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\android-ndk-r9c\platforms\android-14\arch-arm -idirafter =\usr\include -idirafter 
  C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\android-ndk-r9c\sources\cxx-stl\gnu-libstdc++\4.8\include -idirafter 
  C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\android-ndk-r9c\sources\cxx-stl\gnu-libstdc++\4.8\libs\armeabi-v7a\include -idirafter 
  C:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\android-ndk-r9c\sources\android\native_app_glue -I 
  "C:\Users\Public\Documents\Embarcadero\Studio\15.0\Samples\CPP\Mobile Snippets\WebBrowser" -isystem "c:\program files 
  (x86)\embarcadero\studio\15.0\include" -isystem "c:\program files (x86)\embarcadero\studio\15.0\include\android\rtl" -isystem "c:\program files 
  (x86)\embarcadero\studio\15.0\include\android\fmx" -isystem "c:\program files (x86)\embarcadero\studio\15.0\include\android\crtl" -g 
  -fno-limit-debug-info -fborland-extensions -fborland-auto-refcount -nobuiltininc -nostdsysteminc -triple thumbv7-none-linux-androideabi -emit-obj 
  -mconstructor-aliases -pic-level 2 -target-abi aapcs-linux  -nostdinc++ -fdeprecated-macro -fexceptions -fcxx-exceptions -munwind-tables 
  -mstackrealign -fno-spell-checking -fno-use-cxa-atexit -main-file-name uMain.cpp -x c++ -std=c++11 -O0 -tU -o .\Android\Debug\uMain.o 
  -dependency-file .\Android\Debug\uMain.d -MT .\Android\Debug\uMain.o uMain.cpp 
[bccaarm Error] Android.JNI.Toast.hpp(36): expected a class or namespace
[bccaarm Error] Android.JNI.Toast.hpp(36): reference to 'Android' is ambiguous
  Android.JNI.Toast.hpp(28): candidate found by name lookup is 'Android'
  FMX.Helpers.Android.hpp(28): candidate found by name lookup is 'Fmx::Helpers::Android'
[bccaarm Error] Android.JNI.Toast.hpp(36): expected unqualified-id
[bccaarm Error] Android.JNI.Toast.hpp(47): expected a class or namespace
[bccaarm Error] Android.JNI.Toast.hpp(47): reference to 'Android' is ambiguous
  Android.JNI.Toast.hpp(28): candidate found by name lookup is 'Android'
  FMX.Helpers.Android.hpp(28): candidate found by name lookup is 'Fmx::Helpers::Android'
[bccaarm Error] Android.JNI.Toast.hpp(47): expected namespace name
[bccaarm Error] Android.JNI.Toast.hpp(50): expected a class or namespace
[bccaarm Error] Android.JNI.Toast.hpp(50): reference to 'Android' is ambiguous
  Android.JNI.Toast.hpp(28): candidate found by name lookup is 'Android'
  FMX.Helpers.Android.hpp(28): candidate found by name lookup is 'Fmx::Helpers::Android'
[bccaarm Error] Android.JNI.Toast.hpp(50): expected namespace name
[bccaarm Error] Android.JNI.Toast.hpp(53): reference to 'Android' is ambiguous
  Android.JNI.Toast.hpp(28): candidate found by name lookup is 'Android'
  FMX.Helpers.Android.hpp(28): candidate found by name lookup is 'Fmx::Helpers::Android'
[bccaarm Error] uMain.cpp(32): use of undeclared identifier 'Toast'
Failed
Elapsed time: 00:00:05.8

编辑:

新的日志文件:

[bccaarm Error] Androidapi.JNI.Toast.hpp(36): no type named 'Toast' in namespace 'Androidapi::Jni'
[bccaarm Error] Androidapi.JNI.Toast.hpp(36): expected unqualified-id
[bccaarm Error] uMain.cpp(32): unexpected namespace name 'Toast': expected expression
Failed

从现在开始,非常感谢。

【问题讨论】:

  • Androidapi::Jni::ToastToast()的返回值中需要为void,而TToastLength仍然完全没有定义。停止手动编辑格式错误的 .hpp 文件,让 IDE 自动为您生成正确的 .hpp 文件。
  • 如何让 IDE 为我工作?
  • 将 .pas 文件添加到 C++ 项目中,保存项目,然后告诉 IDE 编译 .pas 文件。它将生成一个 .hpp 文件。或者,您可以使用/JPHNE/JL参数调用命令行Delphi编译器(dcc32.exe)直接编译.pas文件。

标签: c++ delphi java-native-interface c++builder c++builder-xe7


【解决方案1】:

.hpp 文件格式错误。

.pas 文件的interface 部分中定义的公共类型均未在.hpp 文件中定义。特别是缺少TToastLength 枚举。而Toast() 在.pas 文件中被声明为procedure,因此没有返回值,但在.hpp 文件中有一个(错误的)返回值。

您(或其他人)是否手动创建了 .hpp 文件?我怀疑是这种情况,有两个明显的原因:

  1. 初始#ifndef/#define 中的Android_JNI_ToastHPP 定义与对应#endif 中的Fmx_Helpers_AndroidHPP 不匹配。

  2. Delphi 编译器总是通过首字母大写和其余字母小写来为 Pascal 单元名称命名 C++ 命名空间,但此 .hpp 文件具有全大写的 JNI 命名空间。

Delphi 编译器不会犯这些错误。

话虽如此,Android.JNI.Toast.pas 应重命名为 Androidapi.JNI.Toast.pas(并重命名 .hpp 文件并相应更新其命名空间)以与 Embarcadero 的其他 JNI 单元保持一致(并与 this article 中的示例相匹配)。这也应该有助于缓解reference to 'Android' is ambiguous 错误。

我强烈建议您更正 .pas 文件,通过 Delphi 编译器运行一次以生成正确的 .hpp 文件,然后在 C++ 代码中按原样使用它。

Androidapi.JNI.Toast.pas:

unit Androidapi.JNI.Toast;

interface

{$IFDEF ANDROID}

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText;

type
  TToastLength = (LongToast, ShortToast);

  JToast = interface;

  JToastClass = interface(JObjectClass)
    ['{69E2D233-B9D3-4F3E-B882-474C8E1D50E9}']
    { Property methods }
    function _GetLENGTH_LONG: Integer; cdecl;
    function _GetLENGTH_SHORT: Integer; cdecl;
    { Methods }
    function init(context: JContext): JToast; cdecl; overload;
    function makeText(context: JContext; text: JCharSequence; duration: Integer)
      : JToast; cdecl;
    { Properties }
    property LENGTH_LONG: Integer read _GetLENGTH_LONG;
    property LENGTH_SHORT: Integer read _GetLENGTH_SHORT;
  end;

  [JavaSignature('android/widget/Toast')]
  JToast = interface(JObject)
    ['{FD81CC32-BFBC-4838-8893-9DD01DE47B00}']
    { Methods }
    procedure cancel; cdecl;
    function getDuration: Integer; cdecl;
    function getGravity: Integer; cdecl;
    function getHorizontalMargin: Single; cdecl;
    function getVerticalMargin: Single; cdecl;
    function getView: JView; cdecl;
    function getXOffset: Integer; cdecl;
    function getYOffset: Integer; cdecl;
    procedure setDuration(value: Integer); cdecl;
    procedure setGravity(gravity, xOffset, yOffset: Integer); cdecl;
    procedure setMargin(horizontalMargin, verticalMargin: Single); cdecl;
    procedure setText(s: JCharSequence); cdecl;
    procedure setView(view: JView); cdecl;
    procedure show; cdecl;
  end;

  TJToast = class(TJavaGenericImport<JToastClass, JToast>)
  end;

procedure Toast(const Msg: string; duration: TToastLength = ShortToast);

{$ENDIF}

implementation

{$IFDEF ANDROID}

uses
  FMX.Helpers.Android, Androidapi.Helpers;

procedure Toast(const Msg: string; duration: TToastLength);
var
  ToastLength: Integer;
begin
  if duration = ShortToast then
    ToastLength := TJToast.JavaClass.LENGTH_SHORT
  else
    ToastLength := TJToast.JavaClass.LENGTH_LONG;
  CallInUiThread(
    procedure
    begin
      TJToast.JavaClass.makeText(SharedActivityContext, StrToJCharSequence(Msg),
        ToastLength).show
    end);
end;
{$ENDIF}

end.

Androidapi.JNI.Toast.hpp:

// CodeGear C++Builder
// Copyright (c) 1995, 2014 by Embarcadero Technologies, Inc.
// All rights reserved

// (DO NOT EDIT: machine generated header) 'Androidapi.JNI.Toast.pas' rev: 28.00 (Android)

#ifndef Androidapi_Jni_ToastHPP
#define Androidapi_Jni_ToastHPP

#pragma delphiheader begin
#pragma option push
#pragma option -w-      // All warnings off
#pragma option -Vx      // Zero-length empty class member 
#pragma pack(push,8)
#include <System.hpp>   // Pascal unit
#include <SysInit.hpp>  // Pascal unit
#include <Androidapi.JNIBridge.hpp> // Pascal unit
#include <Androidapi.JNI.JavaTypes.hpp> // Pascal unit
#include <Androidapi.JNI.GraphicsContentViewText.hpp>   // Pascal unit
#include <System.Rtti.hpp>  // Pascal unit

//-- user supplied -----------------------------------------------------------

namespace Androidapi
{
namespace Jni
{
namespace Toast
{
//-- type declarations -------------------------------------------------------
enum DECLSPEC_DENUM TToastLength : unsigned char { LongToast, ShortToast };

__interface JToastClass;
typedef System::DelphiInterface<JToastClass> _di_JToastClass;
__interface JToast;
typedef System::DelphiInterface<JToast> _di_JToast;
__interface  INTERFACE_UUID("{69E2D233-B9D3-4F3E-B882-474C8E1D50E9}") JToastClass  : public Androidapi::Jni::Javatypes::JObjectClass 
{

public:
    virtual int __cdecl _GetLENGTH_LONG(void) = 0 ;
    virtual int __cdecl _GetLENGTH_SHORT(void) = 0 ;
    HIDESBASE virtual _di_JToast __cdecl init(Androidapi::Jni::Graphicscontentviewtext::_di_JContext context) = 0 /* overload */;
    virtual _di_JToast __cdecl makeText(Androidapi::Jni::Graphicscontentviewtext::_di_JContext context, Androidapi::Jni::Javatypes::_di_JCharSequence text, int duration) = 0 ;
    __property int LENGTH_LONG = {read=_GetLENGTH_LONG};
    __property int LENGTH_SHORT = {read=_GetLENGTH_SHORT};
};

__interface  INTERFACE_UUID("{FD81CC32-BFBC-4838-8893-9DD01DE47B00}") JToast  : public Androidapi::Jni::Javatypes::JObject 
{

public:
    virtual void __cdecl cancel(void) = 0 ;
    virtual int __cdecl getDuration(void) = 0 ;
    virtual int __cdecl getGravity(void) = 0 ;
    virtual float __cdecl getHorizontalMargin(void) = 0 ;
    virtual float __cdecl getVerticalMargin(void) = 0 ;
    virtual Androidapi::Jni::Graphicscontentviewtext::_di_JView __cdecl getView(void) = 0 ;
    virtual int __cdecl getXOffset(void) = 0 ;
    virtual int __cdecl getYOffset(void) = 0 ;
    virtual void __cdecl setDuration(int value) = 0 ;
    virtual void __cdecl setGravity(int gravity, int xOffset, int yOffset) = 0 ;
    virtual void __cdecl setMargin(float horizontalMargin, float verticalMargin) = 0 ;
    virtual void __cdecl setText(Androidapi::Jni::Javatypes::_di_JCharSequence s) = 0 ;
    virtual void __cdecl setView(Androidapi::Jni::Graphicscontentviewtext::_di_JView view) = 0 ;
    virtual void __cdecl show(void) = 0 ;
};

class DELPHICLASS TJToast;
#pragma pack(push,4)
class PASCALIMPLEMENTATION TJToast : public Androidapi::Jnibridge::TJavaGenericImport__2<_di_JToastClass,_di_JToast> 
{
    typedef Androidapi::Jnibridge::TJavaGenericImport__2<_di_JToastClass,_di_JToast>  inherited;

public:
    /* TJavaImport.Create */ inline __fastcall TJToast(void * ID, void * ClsID, Androidapi::Jnibridge::TJavaVTable* VTable) : Androidapi::Jnibridge::TJavaGenericImport__2<_di_JToastClass,_di_JToast> (ID, ClsID, VTable) { }
    /* TJavaImport.Destroy */ inline __fastcall virtual ~TJToast(void) { }

};

#pragma pack(pop)

//-- var, const, procedure ---------------------------------------------------
extern DELPHI_PACKAGE void __fastcall Toast(const System::UnicodeString Msg, TToastLength duration = (TToastLength)(0x1));
}   /* namespace Toast */
}   /* namespace Jni */
}   /* namespace Androidapi */
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROIDAPI_JNI_TOAST)
using namespace Androidapi::Jni::Toast;
#endif
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROIDAPI_JNI)
using namespace Androidapi::Jni;
#endif
#if !defined(DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE) && !defined(NO_USING_NAMESPACE_ANDROIDAPI)
using namespace Androidapi;
#endif
#pragma pack(pop)
#pragma option pop

#pragma delphiheader end.
//-- end unit ----------------------------------------------------------------
#endif  // Androidapi_Jni_ToastHPP

【讨论】:

  • 我在那个文件中做了一些修改,我的错误比以前少了...我在 '__fastcall Toast ...' 之前添加了 'void' 所以,它说它不返回任何值.关于你说的两点,这是因为我从 program files\Embarcadero\Studio\15\includes\android\rtl 中获得了一些文件,并复制了一些我认为需要让它工作的项目......添加“void”后并将 JNI 命名空间重命名为“Jni”我现在只有三个错误,你能帮我解决这个问题吗?
  • 我已经添加了 XE7 的 Delphi 编译器为 .hpp 文件自动生成的确切代码。它在 C++ 中对我来说编译得很好。
  • 非常感谢!您是如何将其从 .pas 转换为 .cpp 的?是像我一样自动还是手动?另一个与此相关的问题。我不能像以前那样直接从 .hpp 源文件调用 delphi 包吗?我问它是因为我在开始制作这个文件之前看到了 Androidapi.IOUtils.hpp 文件作为示例,所以它只是调用了一个 pascal extern。
  • 就像我说的,IDE 可以为您完成。将 .pas 文件添加到 C++ 项目,保存项目,然后告诉 IDE 编译 .pas 文件。它将生成一个 .hpp 文件。是的,C++ 代码可以调用 Delphi 包。这就是为什么 Delphi 编译器首先可以生成 .hpp 文件,以使这些调用成为可能。
  • 你好,又是我。在 C++ Builder Seattle (AppMethod) 中使用这个自动生成的文件时,我遇到了一些问题。现在我无法在我的应用程序中使用 .pas 文件。因此,当我包含 时,我无法将它链接到我的应用程序到标题的功能。我应该打开另一个话题还是可以在这里讨论?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-05
  • 2020-03-12
相关资源
最近更新 更多