Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[webview_flutter_wkwebview] Implement one callback method for review of the design #5700

Merged
merged 44 commits into from
Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7c363fd
dart side of implementation
bparrishMines May 11, 2022
2e55266
objc side of callback impl
bparrishMines May 12, 2022
4a12eaa
documentation and a test messenger
bparrishMines May 12, 2022
6bc048b
dart side update
bparrishMines May 16, 2022
4efa9a1
objc side
bparrishMines May 16, 2022
f9d54e2
formatting
bparrishMines May 16, 2022
2f73074
Merge branch 'main' of github.com:flutter/plugins into callbacks
bparrishMines May 16, 2022
ddfde5c
handles
bparrishMines May 17, 2022
96c21ae
some fixes for PR comments
bparrishMines May 18, 2022
f2a3504
new instance manager
bparrishMines May 19, 2022
77da52f
bunch of work
bparrishMines May 19, 2022
e388090
instance manager tests
bparrishMines May 19, 2022
ac3a2de
fix foundation tests
bparrishMines May 19, 2022
696c25c
dart touchups
bparrishMines May 19, 2022
88816c9
finish dart standardization and support earlier versions
bparrishMines May 19, 2022
9d25ab1
fix dart instance manager
bparrishMines May 19, 2022
4d7ebc4
instance manager ish
bparrishMines May 19, 2022
81b201f
most tests passing
bparrishMines May 19, 2022
62581ba
instance manager tests
bparrishMines May 20, 2022
f0d2498
formatting and one last test
bparrishMines May 20, 2022
4bd6d2a
formatting
bparrishMines May 20, 2022
7974d56
naming
bparrishMines May 20, 2022
ad9b4e6
better comment
bparrishMines May 20, 2022
d8b720e
update comment with info about platform/flutter
bparrishMines May 23, 2022
3c98004
fix bug from instance manager identifier
bparrishMines May 24, 2022
368fb30
limits on identifiers
bparrishMines May 25, 2022
a6980c5
use removeReference name instead
bparrishMines May 25, 2022
179f109
maybe an even better name?
bparrishMines May 25, 2022
e966816
use init constructor
bparrishMines May 25, 2022
3897535
version bump
bparrishMines May 25, 2022
312825a
update name
bparrishMines May 25, 2022
36fa0a0
Merge branch 'main' of github.com:flutter/plugins into callbacks
bparrishMines May 25, 2022
2b7a9af
undo changes to webview_flutter
bparrishMines May 25, 2022
86b193a
add api impls
bparrishMines May 25, 2022
61d5f8a
undo changes to create methods
bparrishMines May 25, 2022
29e8ad0
changes and stuff
bparrishMines May 25, 2022
2be09aa
some updates
bparrishMines May 26, 2022
e212aa4
Merge branch 'main' of github.com:flutter/plugins into callbacks
bparrishMines May 26, 2022
ea0fe93
method names
bparrishMines May 26, 2022
9e47dda
more docs, yay
bparrishMines May 26, 2022
8076bed
spelling and docs
bparrishMines May 31, 2022
0fa7a14
pr comments
bparrishMines Jun 2, 2022
797d448
format and issue
bparrishMines Jun 2, 2022
ba8161a
Merge branch 'main' of github.com:flutter/plugins into callbacks
bparrishMines Jun 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,96 @@

#import <OCMock/OCMock.h>

// Used to test that a FlutterBinaryMessenger with a strong reference to a host api won't
// lead to a circular reference.
@interface FWFTestMessenger : NSObject <FlutterBinaryMessenger>
@property(strong, nullable) id hostApi;
bparrishMines marked this conversation as resolved.
Show resolved Hide resolved
@end

@implementation FWFTestMessenger
- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection {
}

- (void)sendOnChannel:(nonnull NSString *)channel message:(NSData *_Nullable)message {
}

- (void)sendOnChannel:(nonnull NSString *)channel
message:(NSData *_Nullable)message
binaryReply:(FlutterBinaryReply _Nullable)callback {
}

- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(nonnull NSString *)channel
binaryMessageHandler:
(FlutterBinaryMessageHandler _Nullable)handler {
return 0;
}
@end

@interface FWFNavigationDelegateHostApiTests : XCTestCase
@end

@implementation FWFNavigationDelegateHostApiTests
- (void)testCreateWithIdentifier {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
FWFNavigationDelegateHostApiImpl *hostApi =
[[FWFNavigationDelegateHostApiImpl alloc] initWithInstanceManager:instanceManager];
FWFNavigationDelegateHostApiImpl *hostApi = [[FWFNavigationDelegateHostApiImpl alloc]
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];

FlutterError *error;
[hostApi createWithIdentifier:@0 error:&error];
[hostApi createWithIdentifier:@0 didFinishNavigationIdentifier:nil error:&error];
FWFNavigationDelegate *navigationDelegate =
(FWFNavigationDelegate *)[instanceManager instanceForIdentifier:0];

XCTAssertTrue([navigationDelegate conformsToProtocol:@protocol(WKNavigationDelegate)]);
XCTAssertNil(error);
}

- (void)testDidFinishNavigation {
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
FWFNavigationDelegateHostApiImpl *hostApi = [[FWFNavigationDelegateHostApiImpl alloc]
bparrishMines marked this conversation as resolved.
Show resolved Hide resolved
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];

FlutterError *error;
[hostApi createWithIdentifier:@0 didFinishNavigationIdentifier:@1 error:&error];
FWFNavigationDelegate *navigationDelegate =
(FWFNavigationDelegate *)[instanceManager instanceForIdentifier:0];
id mockDelegate = OCMPartialMock(navigationDelegate);

FWFNavigationDelegateFlutterApiImpl *flutterApi = [[FWFNavigationDelegateFlutterApiImpl alloc]
initWithBinaryMessenger:OCMProtocolMock(@protocol(FlutterBinaryMessenger))
instanceManager:instanceManager];
id mockFlutterApi = OCMPartialMock(flutterApi);

OCMStub([mockDelegate navigationDelegateApi]).andReturn(mockFlutterApi);

WKWebView *mockWebView = OCMClassMock([WKWebView class]);
OCMStub([mockWebView URL]).andReturn([NSURL URLWithString:@"https://flutter.dev/"]);
[instanceManager addInstance:mockWebView withIdentifier:2];

[mockDelegate webView:mockWebView didFinishNavigation:OCMClassMock([WKNavigation class])];
OCMVerify([mockFlutterApi didFinishNavigationFunctionWithIdentifier:@1
webViewIdentifier:@2
URL:@"https://flutter.dev/"
completion:OCMOCK_ANY]);
}

- (void)testInstanceCanBeReleasedWhenInstanceManagerIsReleased {
FWFTestMessenger *testMessenger = [[FWFTestMessenger alloc] init];
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
FWFNavigationDelegateHostApiImpl *hostApi =
[[FWFNavigationDelegateHostApiImpl alloc] initWithBinaryMessenger:testMessenger
instanceManager:instanceManager];

testMessenger.hostApi = hostApi;

FlutterError *error;
[hostApi createWithIdentifier:@0 didFinishNavigationIdentifier:nil error:&error];
FWFNavigationDelegate __weak *navigationDelegate =
(FWFNavigationDelegate *)[instanceManager instanceForIdentifier:0];

XCTAssertNotNil(navigationDelegate);
instanceManager = nil;
XCTAssertNil(navigationDelegate);
}
@end
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,9 @@ extern void FWFWKScriptMessageHandlerHostApiSetup(
NSObject<FlutterMessageCodec> *FWFWKNavigationDelegateHostApiGetCodec(void);

@protocol FWFWKNavigationDelegateHostApi
- (void)createWithIdentifier:(NSNumber *)instanceId error:(FlutterError *_Nullable *_Nonnull)error;
- (void)setDidFinishNavigationForDelegateWithIdentifier:(NSNumber *)instanceId
functionIdentifier:(nullable NSNumber *)functionInstanceId
error:(FlutterError *_Nullable *_Nonnull)error;
- (void)createWithIdentifier:(NSNumber *)instanceId
didFinishNavigationIdentifier:(nullable NSNumber *)didFinishNavigationInstanceId
error:(FlutterError *_Nullable *_Nonnull)error;
@end

extern void FWFWKNavigationDelegateHostApiSetup(
Expand All @@ -317,10 +316,10 @@ NSObject<FlutterMessageCodec> *FWFWKNavigationDelegateFlutterApiGetCodec(void);

@interface FWFWKNavigationDelegateFlutterApi : NSObject
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
- (void)didFinishNavigationForDelegateWithIdentifier:(NSNumber *)functionInstanceId
webViewIdentifier:(NSNumber *)webViewInstanceId
URL:(nullable NSString *)url
completion:(void (^)(NSError *_Nullable))completion;
- (void)didFinishNavigationFunctionWithIdentifier:(NSNumber *)functionInstanceId
webViewIdentifier:(NSNumber *)webViewInstanceId
URL:(nullable NSString *)url
completion:(void (^)(NSError *_Nullable))completion;
@end
/// The codec used by FWFNSObjectHostApi.
NSObject<FlutterMessageCodec> *FWFNSObjectHostApiGetCodec(void);
Expand All @@ -343,6 +342,12 @@ NSObject<FlutterMessageCodec> *FWFNSObjectHostApiGetCodec(void);
extern void FWFNSObjectHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
NSObject<FWFNSObjectHostApi> *_Nullable api);

/// The codec used by FWFNSObjectFlutterApi.
NSObject<FlutterMessageCodec> *FWFNSObjectFlutterApiGetCodec(void);

@interface FWFNSObjectFlutterApi : NSObject
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;
@end
/// The codec used by FWFFunctionFlutterApi.
NSObject<FlutterMessageCodec> *FWFFunctionFlutterApiGetCodec(void);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1130,41 +1130,19 @@ void FWFWKNavigationDelegateHostApiSetup(id<FlutterBinaryMessenger> binaryMessen
binaryMessenger:binaryMessenger
codec:FWFWKNavigationDelegateHostApiGetCodec()];
if (api) {
NSCAssert([api respondsToSelector:@selector(createWithIdentifier:error:)],
NSCAssert([api respondsToSelector:@selector(createWithIdentifier:
didFinishNavigationIdentifier:error:)],
@"FWFWKNavigationDelegateHostApi api (%@) doesn't respond to "
@"@selector(createWithIdentifier:error:)",
@"@selector(createWithIdentifier:didFinishNavigationIdentifier:error:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
NSNumber *arg_instanceId = GetNullableObjectAtIndex(args, 0);
NSNumber *arg_didFinishNavigationInstanceId = GetNullableObjectAtIndex(args, 1);
FlutterError *error;
[api createWithIdentifier:arg_instanceId error:&error];
callback(wrapResult(nil, error));
}];
} else {
[channel setMessageHandler:nil];
}
}
{
FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
initWithName:@"dev.flutter.pigeon.WKNavigationDelegateHostApi.setDidFinishNavigation"
binaryMessenger:binaryMessenger
codec:FWFWKNavigationDelegateHostApiGetCodec()];
if (api) {
NSCAssert(
[api respondsToSelector:@selector
(setDidFinishNavigationForDelegateWithIdentifier:functionIdentifier:error:)],
@"FWFWKNavigationDelegateHostApi api (%@) doesn't respond to "
@"@selector(setDidFinishNavigationForDelegateWithIdentifier:functionIdentifier:error:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
NSNumber *arg_instanceId = GetNullableObjectAtIndex(args, 0);
NSNumber *arg_functionInstanceId = GetNullableObjectAtIndex(args, 1);
FlutterError *error;
[api setDidFinishNavigationForDelegateWithIdentifier:arg_instanceId
functionIdentifier:arg_functionInstanceId
error:&error];
[api createWithIdentifier:arg_instanceId
didFinishNavigationIdentifier:arg_didFinishNavigationInstanceId
error:&error];
callback(wrapResult(nil, error));
}];
} else {
Expand Down Expand Up @@ -1217,10 +1195,10 @@ - (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)bina
}
return self;
}
- (void)didFinishNavigationForDelegateWithIdentifier:(NSNumber *)arg_functionInstanceId
webViewIdentifier:(NSNumber *)arg_webViewInstanceId
URL:(nullable NSString *)arg_url
completion:(void (^)(NSError *_Nullable))completion {
- (void)didFinishNavigationFunctionWithIdentifier:(NSNumber *)arg_functionInstanceId
webViewIdentifier:(NSNumber *)arg_webViewInstanceId
URL:(nullable NSString *)arg_url
completion:(void (^)(NSError *_Nullable))completion {
FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel
messageChannelWithName:
@"dev.flutter.pigeon.WKNavigationDelegateFlutterApi.didFinishNavigation"
Expand Down Expand Up @@ -1369,6 +1347,52 @@ void FWFNSObjectHostApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
}
}
}
@interface FWFNSObjectFlutterApiCodecReader : FlutterStandardReader
@end
@implementation FWFNSObjectFlutterApiCodecReader
@end

@interface FWFNSObjectFlutterApiCodecWriter : FlutterStandardWriter
@end
@implementation FWFNSObjectFlutterApiCodecWriter
@end

@interface FWFNSObjectFlutterApiCodecReaderWriter : FlutterStandardReaderWriter
@end
@implementation FWFNSObjectFlutterApiCodecReaderWriter
- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data {
return [[FWFNSObjectFlutterApiCodecWriter alloc] initWithData:data];
}
- (FlutterStandardReader *)readerWithData:(NSData *)data {
return [[FWFNSObjectFlutterApiCodecReader alloc] initWithData:data];
}
@end

NSObject<FlutterMessageCodec> *FWFNSObjectFlutterApiGetCodec() {
static dispatch_once_t sPred = 0;
static FlutterStandardMessageCodec *sSharedObject = nil;
dispatch_once(&sPred, ^{
FWFNSObjectFlutterApiCodecReaderWriter *readerWriter =
[[FWFNSObjectFlutterApiCodecReaderWriter alloc] init];
sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];
});
return sSharedObject;
}

@interface FWFNSObjectFlutterApi ()
@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;
@end

@implementation FWFNSObjectFlutterApi

- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger {
self = [super init];
if (self) {
_binaryMessenger = binaryMessenger;
}
return self;
}
@end
@interface FWFFunctionFlutterApiCodecReader : FlutterStandardReader
@end
@implementation FWFFunctionFlutterApiCodecReader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,25 @@

#import "FWFGeneratedWebKitApis.h"
#import "FWFInstanceManager.h"
#import "FWFObjectHostApi.h"

NS_ASSUME_NONNULL_BEGIN

/**
* Flutter api implementation for WKNavigationDelegate.
*
* Handles making callbacks to Dart for a WKNavigationDelegate.
*/
@interface FWFNavigationDelegateFlutterApiImpl : FWFWKNavigationDelegateFlutterApi
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
instanceManager:(FWFInstanceManager *)instanceManager;
@end

/**
* Implementation of WKNavigationDelegate for FWFNavigationDelegateHostApiImpl.
*/
@interface FWFNavigationDelegate : NSObject <WKNavigationDelegate>
@interface FWFNavigationDelegate : FWFObject <WKNavigationDelegate>
@property(readonly, nonnull) FWFNavigationDelegateFlutterApiImpl *navigationDelegateApi;
bparrishMines marked this conversation as resolved.
Show resolved Hide resolved
@end

/**
Expand All @@ -22,7 +34,8 @@ NS_ASSUME_NONNULL_BEGIN
* Handles creating WKNavigationDelegate that intercommunicate with a paired Dart object.
*/
@interface FWFNavigationDelegateHostApiImpl : NSObject <FWFWKNavigationDelegateHostApi>
- (instancetype)initWithInstanceManager:(FWFInstanceManager *)instanceManager;
- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger
instanceManager:(FWFInstanceManager *)instanceManager;
@end

NS_ASSUME_NONNULL_END
Loading