Создание экземпляра Android SipManager в C ++ Builder - PullRequest
0 голосов
/ 12 сентября 2018

Я пытаюсь создать экземпляр SipManager (developer.android.com) в Embarcadero с помощью конструктора c ++, но не могу найти правильный путь.Для этого я использую экземпляры Delphi Interface.

В Java это выглядит так:

public static SipManager manager;
manager = SipManager.newInstance(context);
//Context is the application context for creating the manager object.

Для правильной компиляции кода, который появится далее, необходимо включитьследующее:

#include <System.Classes.hpp>
#if defined (_PLAT_ANDROID)
    #include <Androidapi.Helpers.HPP>
    #include <Androidapi.JNI.Net.HPP>
    #include <Androidapi.JNI.os.HPP>
    #include <Androidapi.JNI.Support.HPP>
    #include <Androidapi.JNI.Media.HPP>
#endif

Кроме того, в манифест необходимо добавить разрешения «Использовать Sip» и «Интернет».

Я пытался сделать это разными способами, основываясь натот факт, что я уже знал, как установить WifiManager:

#if defined (_PLAT_ANDROID)
    _di_JObject obj;
    _diJWifiManager wm;
    obj = SharedActivityContext()->getSystemService(TJContext::JavaClass->WIFI_SERVICE);
    wm = TJWifiManager::Wrap(((_di_ILocalObject)obj)->GetObjectID());
    wm->setWifiEnabled(true);
#endif

Для своего приложения я сделал следующее:

  1. Это компилируется, но при запуске приложения оноговорит, что метод init () не найден.

    #if defined (_PLAT_ANDROID)
        _di_JObject obj;
        _di_JSipManager sipm;
        obj = TJSipManager::JavaClass->init();
        sipm = TJSipManager::Wrap(((_di_ILocalObject)obj)->GetObjectID());
    #endif
    
  2. Он также компилируется, но при запуске приложения у него есть исключение типа "Abort".

    #if defined (_PLAT_ANDROID)
        _di_JSipManager sipm;
        sipm = TJSipManager::Create();
    #endif
    
  3. Это тоже компилируется, но при запуске приложения это исключение типа "Нарушение прав доступа".

    #if defined (_PLAT_ANDROID)
        _di_JSipManager sipm;
        sipm = TJSipManager::JavaClass;
    #endif
    
  4. Этотоже компилируется, но при попытке открыть профиль имеет вид исключения «Abort».

    #if defined (_PLAT_ANDROID)
        _di_JSipManager sipm;
        _di_JContext context;
        _di_JSipProfileBuilder sippb;
        _di_JSipProfile sipp;
        context = SharedActivityContext()->getApplicationContext();
        TJSipManager *sipn = new TJSipManager();
        sipm = sipn->Wrap(((_di_ILocalObject)context) >GetObjectID());
        _di_JString uri;
        uri = StringToJString("sip:165@40.134.279.145:5060");
        sippb = TJSipProfile_Builder::JavaClass->init(uri);
        sipp = sippb->build();
        sipm->open(sipp);
    #endif
    

Если я выполняю только часть SipProfile, проблем нет, и профиль создается.

#if defined (_PLAT_ANDROID)
    _di_JSipProfileBuilder sippb;
    _di_JSipProfile sipp;
    _di_JString uri;
    uri = StringToJString("sip:165@40.134.279.145:5060");
    sippb = TJSipProfile_Builder::JavaClass->init(uri);
    sipp = sippb->build();
#endif

И в Java это так:

public static SipProfile me;
SipProfile.Builder builder = new SipProfile.Builder("uri");
me = builder.build();

Я хотел бы знать, как создать экземпляр SipManager for c ++ builder.В Java было замечено, что он использует метод "newInstance (context)" для него, но когда я пытаюсь создать его экземпляр в C ++ Builder, он не обнаруживает аналогичного метода, принадлежащего этому классу.

  1. Можно ли создать экземпляр в C ++ Builder?

  2. Какой правильный способ сделать это?

  3. Если это невозможно,есть ли другая библиотека для создания Sip-приложения в Embarcadero с помощью сборщика c ++?


На другом форуме Реми ответил:

"Это ДОЛЖНО быть чем-то простымкак это в C ++ Builder:

#if defined (_PLAT_ANDROID)
    _di_JSipManager manager = TJSipManager::JavaClass->newInstance(SharedActivityContext());
    // use manager as needed...
#endif

Но на самом деле это не работает (по крайней мере, в Сиэтле, не знаю о более поздних версиях), потому что статический метод newInstance () пропущен изинтерфейс JSipManagerClass в Androidapi.JNI.Net.hpp!

Вы можете попробовать использовать Java2OP для повторного импорта класса SipManager, но я не знаю, будет ли это в конечном итоге страдать от той же проблемы или нет."


Но у меня последний выпуск Tokio aи у меня все еще есть та же проблема.Я попытаюсь повторно импортировать SipManager.

1 Ответ

0 голосов
/ 16 сентября 2018

Давайте рассмотрим ваши предложения и посмотрим, почему они не работают:

1) вы вызываете Java-конструктор без параметров, который отображается как init(), но этот класс не предназначен для создания с помощью обычного конструктора. Предполагается, что конструктор является закрытым, но независимо от того, в документации сказано, что вы создаете экземпляр с помощью newInstance().

2) вызов метода класса Create() для импорта обычно аналогичен вызову init(), но выполняется другим способом. Учитывая, что init недоступен, он терпит неудачу, просто с другим симптомом здесь.

3) Вы объявили переменную типа интерфейса методов экземпляра Delphi JSipManager, но затем присвоили ей свойство JavaClass, которое дает тип интерфейса методов класса Delphi JSipManagerClass. Эти 2 не одинаковы. Ожидается ошибка.

4) Шаблонный класс TJSipManager является помощником для получения доступа к интерфейсу методов класса (через свойство JavaClass) или к методам экземпляра через экземпляр, созданный путем вызова конструктора (может быть, через Create() или JavaClass->init(). Вы не должны создавать экземпляр этого шаблонного класса - он не имеет смысла. Приступая к преобразованию (через Wrap()) объекта контекста в SipManager привкуса отчаяния - это совершенно разные типы.

Хорошо, теперь давайте посмотрим, почему то, что должно работать, не работает.

Причина, по которой метод newInstance() (и другие) закомментирован из интерфейса методов класса JSipManagerClass в исходном модуле Delphi, Androidapi.JNI.Net.pas, заключается в том, что все они имеют параметр или возвращаемый тип. например, JContext или JIntent, который определен и представлен из модуля, который уже использует Androidapi.JNI.Net.pas, а именно из модуля Androidapi.JNI.GraphicsContentViewText.pas.

Java2OP оставил методы там, потому что они существуют, но закомментировал их, чтобы избежать ошибки ссылки на циклические единицы.

Что будет работать, так это переопределить типы SipManager JNI Bridge в новом модуле Delphi, добавить этот новый модуль в проект C ++, включить его сгенерированный заголовок и продолжить оттуда.

Чтобы создать модуль, вы можете щелкнуть правой кнопкой мыши по проекту в Менеджере проектов и выбрать Добавить новый, Модуль - Delphi. Если вы используете только C ++ Builder (без поддержки Delphi), просто создайте модуль в текстовом редакторе. Он называется Androidapi.JNI.SIP.pas и содержит импорт только одного типа: SipManager - чтобы избежать борьбы с неоднозначностью, я назвал базовый интерфейс импорта JSipManager2:

unit Androidapi.JNI.SIP;

interface

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

type
// ===== Forward declarations =====

  JSipManager2 = interface;//android.net.sip.SipManager

  JSipManager2Class = interface(JObjectClass)
    ['{62C12348-C7E4-4B5E-AE75-715EAAFD4465}']
    {class} function _GetEXTRA_CALL_ID: JString; cdecl;
    {class} function _GetEXTRA_OFFER_SD: JString; cdecl;
    {class} function _GetINCOMING_CALL_RESULT_CODE: Integer; cdecl;
    {class} function getCallId(incomingCallIntent: JIntent): JString; cdecl;
    {class} function getOfferSessionDescription(incomingCallIntent: JIntent): JString; cdecl;
    {class} function isApiSupported(context: JContext): Boolean; cdecl;
    {class} function isIncomingCallIntent(intent: JIntent): Boolean; cdecl;
    {class} function isSipWifiOnly(context: JContext): Boolean; cdecl;
    {class} function isVoipSupported(context: JContext): Boolean; cdecl;
    {class} function newInstance(context: JContext): JSipManager2; cdecl;
    {class} property EXTRA_CALL_ID: JString read _GetEXTRA_CALL_ID;
    {class} property EXTRA_OFFER_SD: JString read _GetEXTRA_OFFER_SD;
    {class} property INCOMING_CALL_RESULT_CODE: Integer read _GetINCOMING_CALL_RESULT_CODE;
  end;

  [JavaSignature('android/net/sip/SipManager')]
  JSipManager2 = interface(JObject)
    ['{EDE899E1-4774-41FB-BC53-03BB69565231}']
    procedure close(localProfileUri: JString); cdecl;
    function createSipSession(localProfile: JSipProfile; listener: JSipSession_Listener): JSipSession; cdecl;
    //function getSessionFor(incomingCallIntent: JIntent): JSipSession; cdecl;
    function isOpened(localProfileUri: JString): Boolean; cdecl;
    function isRegistered(localProfileUri: JString): Boolean; cdecl;
    function makeAudioCall(localProfile: JSipProfile; peerProfile: JSipProfile; listener: JSipAudioCall_Listener; timeout: Integer): JSipAudioCall; cdecl; overload;
    function makeAudioCall(localProfileUri: JString; peerProfileUri: JString; listener: JSipAudioCall_Listener; timeout: Integer): JSipAudioCall; cdecl; overload;
    procedure open(localProfile: JSipProfile); cdecl; overload;
    //procedure open(localProfile: JSipProfile; incomingCallPendingIntent: JPendingIntent; listener: JSipRegistrationListener); cdecl; overload;
    procedure register(localProfile: JSipProfile; expiryTime: Integer; listener: JSipRegistrationListener); cdecl;
    procedure setRegistrationListener(localProfileUri: JString; listener: JSipRegistrationListener); cdecl;
    //function takeAudioCall(incomingCallIntent: JIntent; listener: JSipAudioCall_Listener): JSipAudioCall; cdecl;
    procedure unregister(localProfile: JSipProfile; listener: JSipRegistrationListener); cdecl;
  end;
  TJSipManager2 = class(TJavaGenericImport<JSipManager2Class, JSipManager2>) end;

implementation

procedure RegisterTypes;
begin
  TRegTypes.RegisterType('Androidapi.JNI.SIP.JSipManager2', TypeInfo(Androidapi.JNI.SIP.JSipManager2));
end;

initialization
  RegisterTypes;
end.

Затем используйте его в некотором C ++-коде, например так:

...
// Cleanse build of lots of errors about __cdecl...
#define __cdecl
#include "Androidapi.JNI.SIP.hpp"
#include <Androidapi.Helpers.hpp>
...
    _di_JSipManager2 manager = TJSipManager2::JavaClass->newInstance(TAndroidHelper::Context);
    // use manager as needed...

Кажется, это компилируется и выполняется нормально, но у меня нет службы SIP, поэтому я не могу пойти дальше.

Как прощальный комментарий, глобальная функция SharedActivityContext() устарела - класс TAndroidHelper теперь содержит все такие вещи, как статические методы / свойства, такие как TAndroidHelper::Context.

...