Skip to content

Commit dd1e21e

Browse files
[webview_flutter_android] [webview_flutter_wkwebview] Platform implementations for supporting permission requests (#3792)
Platform implementation portion of flutter/packages#3543
1 parent 5e09c54 commit dd1e21e

33 files changed

+1288
-199
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.4.0
2+
3+
* Adds support for `PlatformWebViewController.setOnPlatformPermissionRequest`.
4+
15
## 3.3.0
26

37
* Adds support for `PlatformNavigationDelegate.onUrlChange`.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ Then you will have access to the native class `FWFWebViewFlutterWKWebViewExterna
3434
This package uses [pigeon][3] to generate the communication layer between Flutter and the host
3535
platform (iOS). The communication interface is defined in the `pigeons/web_kit.dart`
3636
file. After editing the communication interface regenerate the communication layer by running
37-
`flutter pub run pigeon --input pigeons/web_kit.dart`.
37+
`dart run pigeon --input pigeons/web_kit.dart`.
3838

3939
Besides [pigeon][3] this package also uses [mockito][4] to generate mock objects for testing
4040
purposes. To generate the mock objects run the following command:
4141
```bash
42-
flutter pub run build_runner build --delete-conflicting-outputs
42+
dart run build_runner build --delete-conflicting-outputs
4343
```
4444

4545
If you would like to contribute to the plugin, check out our [contribution guide][5].

example/ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@
4545
<true/>
4646
<key>UIApplicationSupportsIndirectInputEvents</key>
4747
<true/>
48+
<key>NSCameraUsageDescription</key>
49+
<string>If you want to use the camera, you have to give permission.</string>
4850
</dict>
4951
</plist>

example/ios/RunnerTests/FWFDataConvertersTests.m

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ @interface FWFDataConvertersTests : XCTestCase
1313

1414
@implementation FWFDataConvertersTests
1515
- (void)testFWFNSURLRequestFromRequestData {
16-
NSURLRequest *request = FWFNSURLRequestFromRequestData([FWFNSUrlRequestData
16+
NSURLRequest *request = FWFNativeNSURLRequestFromRequestData([FWFNSUrlRequestData
1717
makeWithUrl:@"https://flutter.dev"
1818
httpMethod:@"post"
1919
httpBody:[FlutterStandardTypedData typedDataWithBytes:[NSData data]]
@@ -27,16 +27,16 @@ - (void)testFWFNSURLRequestFromRequestData {
2727

2828
- (void)testFWFNSURLRequestFromRequestDataDoesNotOverrideDefaultValuesWithNull {
2929
NSURLRequest *request =
30-
FWFNSURLRequestFromRequestData([FWFNSUrlRequestData makeWithUrl:@"https://flutter.dev"
31-
httpMethod:nil
32-
httpBody:nil
33-
allHttpHeaderFields:@{}]);
30+
FWFNativeNSURLRequestFromRequestData([FWFNSUrlRequestData makeWithUrl:@"https://flutter.dev"
31+
httpMethod:nil
32+
httpBody:nil
33+
allHttpHeaderFields:@{}]);
3434

3535
XCTAssertEqualObjects(request.HTTPMethod, @"GET");
3636
}
3737

3838
- (void)testFWFNSHTTPCookieFromCookieData {
39-
NSHTTPCookie *cookie = FWFNSHTTPCookieFromCookieData([FWFNSHttpCookieData
39+
NSHTTPCookie *cookie = FWFNativeNSHTTPCookieFromCookieData([FWFNSHttpCookieData
4040
makeWithPropertyKeys:@[ [FWFNSHttpCookiePropertyKeyEnumData
4141
makeWithValue:FWFNSHttpCookiePropertyKeyEnumName] ]
4242
propertyValues:@[ @"cookieName" ]]);
@@ -45,7 +45,7 @@ - (void)testFWFNSHTTPCookieFromCookieData {
4545
}
4646

4747
- (void)testFWFWKUserScriptFromScriptData {
48-
WKUserScript *userScript = FWFWKUserScriptFromScriptData([FWFWKUserScriptData
48+
WKUserScript *userScript = FWFNativeWKUserScriptFromScriptData([FWFWKUserScriptData
4949
makeWithSource:@"mySource"
5050
injectionTime:[FWFWKUserScriptInjectionTimeEnumData
5151
makeWithValue:FWFWKUserScriptInjectionTimeEnumAtDocumentStart]
@@ -70,7 +70,7 @@ - (void)testFWFWKNavigationActionDataFromNavigationAction {
7070
OCMStub([mockNavigationAction targetFrame]).andReturn(mockFrameInfo);
7171

7272
FWFWKNavigationActionData *data =
73-
FWFWKNavigationActionDataFromNavigationAction(mockNavigationAction);
73+
FWFWKNavigationActionDataFromNativeWKNavigationAction(mockNavigationAction);
7474
XCTAssertNotNil(data);
7575
XCTAssertEqual(data.navigationType, FWFWKNavigationTypeReload);
7676
}
@@ -82,7 +82,7 @@ - (void)testFWFNSUrlRequestDataFromNSURLRequest {
8282
request.HTTPBody = [@"aString" dataUsingEncoding:NSUTF8StringEncoding];
8383
request.allHTTPHeaderFields = @{@"a" : @"field"};
8484

85-
FWFNSUrlRequestData *data = FWFNSUrlRequestDataFromNSURLRequest(request);
85+
FWFNSUrlRequestData *data = FWFNSUrlRequestDataFromNativeNSURLRequest(request);
8686
XCTAssertEqualObjects(data.url, @"https://www.flutter.dev/");
8787
XCTAssertEqualObjects(data.httpMethod, @"POST");
8888
XCTAssertEqualObjects(data.httpBody.data, [@"aString" dataUsingEncoding:NSUTF8StringEncoding]);
@@ -93,7 +93,7 @@ - (void)testFWFWKFrameInfoDataFromWKFrameInfo {
9393
WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]);
9494
OCMStub([mockFrameInfo isMainFrame]).andReturn(YES);
9595

96-
FWFWKFrameInfoData *targetFrameData = FWFWKFrameInfoDataFromWKFrameInfo(mockFrameInfo);
96+
FWFWKFrameInfoData *targetFrameData = FWFWKFrameInfoDataFromNativeWKFrameInfo(mockFrameInfo);
9797
XCTAssertEqualObjects(targetFrameData.isMainFrame, @YES);
9898
}
9999

@@ -102,7 +102,7 @@ - (void)testFWFNSErrorDataFromNSError {
102102
code:23
103103
userInfo:@{NSLocalizedDescriptionKey : @"description"}];
104104

105-
FWFNSErrorData *data = FWFNSErrorDataFromNSError(error);
105+
FWFNSErrorData *data = FWFNSErrorDataFromNativeNSError(error);
106106
XCTAssertEqualObjects(data.code, @23);
107107
XCTAssertEqualObjects(data.domain, @"domain");
108108
XCTAssertEqualObjects(data.localizedDescription, @"description");
@@ -113,8 +113,46 @@ - (void)testFWFWKScriptMessageDataFromWKScriptMessage {
113113
OCMStub([mockScriptMessage name]).andReturn(@"name");
114114
OCMStub([mockScriptMessage body]).andReturn(@"message");
115115

116-
FWFWKScriptMessageData *data = FWFWKScriptMessageDataFromWKScriptMessage(mockScriptMessage);
116+
FWFWKScriptMessageData *data = FWFWKScriptMessageDataFromNativeWKScriptMessage(mockScriptMessage);
117117
XCTAssertEqualObjects(data.name, @"name");
118118
XCTAssertEqualObjects(data.body, @"message");
119119
}
120+
121+
- (void)testFWFWKSecurityOriginDataFromWKSecurityOrigin {
122+
WKSecurityOrigin *mockSecurityOrigin = OCMClassMock([WKSecurityOrigin class]);
123+
OCMStub([mockSecurityOrigin host]).andReturn(@"host");
124+
OCMStub([mockSecurityOrigin port]).andReturn(2);
125+
OCMStub([mockSecurityOrigin protocol]).andReturn(@"protocol");
126+
127+
FWFWKSecurityOriginData *data =
128+
FWFWKSecurityOriginDataFromNativeWKSecurityOrigin(mockSecurityOrigin);
129+
XCTAssertEqualObjects(data.host, @"host");
130+
XCTAssertEqualObjects(data.port, @(2));
131+
XCTAssertEqualObjects(data.protocol, @"protocol");
132+
}
133+
134+
- (void)testFWFWKPermissionDecisionFromData API_AVAILABLE(ios(15.0)) {
135+
XCTAssertEqual(FWFNativeWKPermissionDecisionFromData(
136+
[FWFWKPermissionDecisionData makeWithValue:FWFWKPermissionDecisionDeny]),
137+
WKPermissionDecisionDeny);
138+
XCTAssertEqual(FWFNativeWKPermissionDecisionFromData(
139+
[FWFWKPermissionDecisionData makeWithValue:FWFWKPermissionDecisionGrant]),
140+
WKPermissionDecisionGrant);
141+
XCTAssertEqual(FWFNativeWKPermissionDecisionFromData(
142+
[FWFWKPermissionDecisionData makeWithValue:FWFWKPermissionDecisionPrompt]),
143+
WKPermissionDecisionPrompt);
144+
}
145+
146+
- (void)testFWFWKMediaCaptureTypeDataFromWKMediaCaptureType API_AVAILABLE(ios(15.0)) {
147+
XCTAssertEqual(
148+
FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType(WKMediaCaptureTypeCamera).value,
149+
FWFWKMediaCaptureTypeCamera);
150+
XCTAssertEqual(
151+
FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType(WKMediaCaptureTypeMicrophone).value,
152+
FWFWKMediaCaptureTypeMicrophone);
153+
XCTAssertEqual(
154+
FWFWKMediaCaptureTypeDataFromNativeWKMediaCaptureType(WKMediaCaptureTypeCameraAndMicrophone)
155+
.value,
156+
FWFWKMediaCaptureTypeCameraAndMicrophone);
157+
}
120158
@end

example/ios/RunnerTests/FWFUIDelegateHostApiTests.m

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,45 @@ - (void)testOnCreateWebViewForDelegateWithIdentifier {
9797
isKindOfClass:[FWFWKNavigationActionData class]]
9898
completion:OCMOCK_ANY]);
9999
}
100+
101+
- (void)testRequestMediaCapturePermissionForOrigin API_AVAILABLE(ios(15.0)) {
102+
FWFInstanceManager *instanceManager = [[FWFInstanceManager alloc] init];
103+
104+
FWFUIDelegate *mockDelegate = [self mockDelegateWithManager:instanceManager identifier:0];
105+
FWFUIDelegateFlutterApiImpl *mockFlutterAPI = [self mockFlutterApiWithManager:instanceManager];
106+
107+
OCMStub([mockDelegate UIDelegateAPI]).andReturn(mockFlutterAPI);
108+
109+
WKWebView *mockWebView = OCMClassMock([WKWebView class]);
110+
[instanceManager addDartCreatedInstance:mockWebView withIdentifier:1];
111+
112+
WKSecurityOrigin *mockSecurityOrigin = OCMClassMock([WKSecurityOrigin class]);
113+
OCMStub([mockSecurityOrigin host]).andReturn(@"");
114+
OCMStub([mockSecurityOrigin port]).andReturn(0);
115+
OCMStub([mockSecurityOrigin protocol]).andReturn(@"");
116+
117+
WKFrameInfo *mockFrameInfo = OCMClassMock([WKFrameInfo class]);
118+
OCMStub([mockFrameInfo isMainFrame]).andReturn(YES);
119+
120+
[mockDelegate webView:mockWebView
121+
requestMediaCapturePermissionForOrigin:mockSecurityOrigin
122+
initiatedByFrame:mockFrameInfo
123+
type:WKMediaCaptureTypeMicrophone
124+
decisionHandler:^(WKPermissionDecision decision){
125+
}];
126+
127+
OCMVerify([mockFlutterAPI
128+
requestMediaCapturePermissionForDelegateWithIdentifier:@0
129+
webViewIdentifier:@1
130+
origin:[OCMArg isKindOfClass:
131+
[FWFWKSecurityOriginData
132+
class]]
133+
frame:[OCMArg
134+
isKindOfClass:[FWFWKFrameInfoData
135+
class]]
136+
type:[OCMArg isKindOfClass:
137+
[FWFWKMediaCaptureTypeData
138+
class]]
139+
completion:OCMOCK_ANY]);
140+
}
100141
@end

example/lib/main.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ Page resource error:
137137
);
138138
},
139139
))
140+
..setOnPlatformPermissionRequest(
141+
(PlatformWebViewPermissionRequest request) {
142+
debugPrint(
143+
'requesting permissions for ${request.types.map((WebViewPermissionResourceType type) => type.name)}',
144+
);
145+
request.grant();
146+
},
147+
)
140148
..loadRequest(LoadRequestParams(
141149
uri: Uri.parse('https://flutter.dev'),
142150
));

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies:
1010
flutter:
1111
sdk: flutter
1212
path_provider: ^2.0.6
13-
webview_flutter_platform_interface: ^2.1.0
13+
webview_flutter_platform_interface: ^2.3.0
1414
webview_flutter_wkwebview:
1515
# When depending on this package from a real application you should use:
1616
# webview_flutter: ^x.y.z

0 commit comments

Comments
 (0)