Перейти к содержанию
  • Регистрация
  • 0
serser

Использование WebView. Отслеживание переходов с помощью decidePolicyForNavigationAction

Вопрос

Помогите портировать интерфейсы для реализации делегата для WebView.setPolicyDelegate, с помощью которого можно запрещать или переопределять переходы по ссылкам.
Отталкивался от хелпа эпла. Реализовал вроде как все, что нужно. Страница гугла открывается, но колбэк делегата не вызывается.

unit MainFormUnit;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,

  Macapi.AppKit,
  Macapi.CocoaTypes,
  Macapi.Foundation,
  Macapi.ObjectiveC, FMX.StdCtrls,

  Posix.Stdlib, Macapi.CoreFoundation, FMX.Platform.Mac,
  System.Generics.Collections;

type
  WebFrameClass = interface(NSObjectClass)
  ['{7BE750C8-DFEC-4870-851A-12DBCB0B78F6}']
  end;

  WebFrame = interface(NSObject)
  ['{BCFA04BE-41AB-4B78-89C0-3330F12C7695}']
    procedure loadRequest(request: NSURLRequest); cdecl;
  end;

  TWebFrame = class(TOCGenericImport<WebFrameClass, WebFrame>)
  end;

  WebViewClass = interface(NSViewClass)
  ['{0D9F44B7-09FD-4E35-B96E-8DB71B9A2537}']
    {class} function canShowMIMEType(MIMEType: NSString): Boolean; cdecl;
  end;

  WebView = interface(NSView)
  ['{C36D8016-2FCB-49F0-BA1C-C9913A37F9AC}']
    procedure clos; cdecl;
    procedure setPolicyDelegate(delegate: Pointer); cdecl;
    procedure setHostWindow(hostWindow: NSWindow); cdecl;
    function initWithFrame(frame: NSRect; frameName: NSString; groupName: NSString): Pointer; cdecl;
    function mainFrame: WebFrame; cdecl;
  end;

  TWebView = class(TOCGenericImport<WebViewClass, WebView>)
  end;

  WebPolicyDecisionListener = interface(IObjectiveC)
  ['{2AD8355D-6C57-410D-A4F4-230C90B6D799}']
    procedure download; cdecl;
    procedure ignore; cdecl;
    procedure use; cdecl;
  end;

  WebViewDelegate = interface(IObjectiveC)
  ['{5B66FF5F-DA92-48D3-A715-C89A68AA8995}']
    procedure decidePolicyForNavigationAction(actionInformation: NSDictionary;
      request: NSURLRequest; frame: WebFrame; listener: WebPolicyDecisionListener); cdecl;
  end;

  TWebViewDelegate = class(TOCLocal, WebViewDelegate)
    procedure decidePolicyForNavigationAction(actionInformation: NSDictionary;
      request: NSURLRequest; frame: WebFrame; listener: WebPolicyDecisionListener); cdecl;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
  public
    MyWebView: WebView;
    MyDelegate: TWebViewDelegate;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  PWebView: Pointer;
  FwkMod: HMODULE;
  urlStr: NSURL;
  urlreq: NSURLRequest;

  MyView: NSView;
const
  WebKitFWK: string = '/System/Library/Frameworks/WebKit.framework/WebKit';
begin
  FwkMod := System.SysUtils.LoadLibrary(PWideChar(WebKitFWK));
  PWebView := TWebView.Alloc.initWithFrame(MakeNSRect(10, 10, 500, 500), nil, nil);
  MyWebView := TWebView.Wrap(PWebView);
  MyWebView.setAutoresizingMask(NSViewHeightSizable or NSViewWidthSizable);
  //MyWebView.setHostWindow(MyNSWindow);

  MyView := WindowHandleToPlatform(Form1.Handle).View;

  MyView.addSubview(MyWebView);

  MyDelegate := TWebViewDelegate.Create;
  MyWebView.setPolicyDelegate((MyDelegate as ILocalObject).GetObjectID);

  urlStr := TNSURL.Wrap(TNSURL.Alloc.initWithString(NSSTR('http://www.google.com/')));
  urlreq := TNSURLRequest.Wrap(TNSURLRequest.Alloc.initWithURL(urlstr));
  MyWebView.mainFrame.loadRequest(urlreq);

  urlStr.release;
  urlreq.release;
end;

{ TWebViewDelegate }

procedure TWebViewDelegate.decidePolicyForNavigationAction(
  actionInformation: NSDictionary; request: NSURLRequest; frame: WebFrame;
  listener: WebPolicyDecisionListener);
begin
  MessageDlg('hi', TMsgDlgType.mtInformation, [TMsgDlgBtn.mbOK], 0);
end;

end.

Также не совсем понятно, где должен располагаться метод webView:decidePolicyForNavigationAction:request:frame:decisionListener. В документации он объявлен как:

- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener>)listener

Т.е. похоже на то, что он должен быть методом класса WebView? Или же методом произвольного класса делегата?

 

И еще, я так понимаю, что полное имя этого метода webView:decidePolicyForNavigationAction:request:frame:decisionListener, то есть объявляя его как decidePolicyForNavigationAction возможно мы лишаем mac os возможности найти его. Но как же тогда объявить его полностью?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Рекомендуемые сообщения

  • 0

Я могу только в понедельник проверить.

 

Но есть предположение. Добавьте конструктор по умолчанию в TWebViewDelegate и внутри вызовите базовый конструктор TOCLocal.

 

Методы протокола делегата должен быть в интерфейсе WebViewDelegate 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вы имеете ввиду вот так?) 

constructor TWebViewDelegate.Create;
begin
  inherited Create;
end;

Это какой-то хак? Попробовал, но ничего не изменилось(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Ошибка в неправильной трансляции методов протокола. В вашем случае:

– webView:decidePolicyForNavigationAction:request:frame:decisionListener:

Должен перейти в (Правильно):

procedure webView(webView1: WebView; decidePolicyForNavigationAction: NSDictionary; request: NSURLRequest; frame: WebFrame; decisionListener: WebPolicyDecisionListener); cdecl;

А не в (Неправильно), потеряли параметр webView :

procedure decidePolicyForNavigationAction(actionInformation: NSDictionary; request: NSURLRequest; frame: WebFrame; listener: WebPolicyDecisionListener); cdecl;

В качестве примера, посмотрите для сравнения, как транслируется CLLocationManagerDelegate:

– locationManager:didFailWithError:
– locationManager:didUpdateToLocation:fromLocation:

В Delphi:

  CLLocationManagerDelegate = interface(IObjectiveC)
    ['{C1794A16-F4FB-46E1-839E-2AFBA43B420C}']
    procedure locationManager(manager: CLLocationManager; didFailWithError: NSError); cdecl; overload;
    procedure locationManager(manager: CLLocationManager; didUpdateToLocation: CLLocation; fromLocation: CLLocation); cdecl; overload;
  end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

О чудо! Оно работает) Спасибо, Ярослав!

 

Я думал, что связывание происходит только по имени метода.

 

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

Первый параметр (webView1 для которого, кстати, не важно имя) является Self-ом, который передается неявно в ObjC, но у нас он выделен явно? В этом случае можно ли использовать дельфевый Self? (Скорее всего можно, но все же)

 

Все-таки что означает первая часть определения, до имени метода:

- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener>)listener

То, что webView является первым параметром, а webView: началом имени или есть какой-то еще смысл?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
  • Первая часть (webView) - название сообщения.
  • Остальное это параметры.

На счет наименования, я не проверял. Но по-моему связь идет по типу параметров, а не по названию. Поэтому, если встречаются два сообщения Objective C с одинаковыми списками типов, но разными параметрами, то в Delphi нужно такие методы помечать атрибутами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Нет-нет, сейчас проверил. Связывается только по имени всех параметров, кроме первого и по имени метода. Причем попробовал тип WebFrame в объявлении заменить на NSURL и делегат все равно вызвался. Спасибо)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...