forked from flutter/plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[webview_flutter] Extract Android implementation into a separate pack…
…age (flutter#4343) * Setup webview_flutter_android package. Creates a new `webview_flutter_android` directory and adds the following meta-data files: - `AUTHORS`: copied from the `webview_flutter` package and added my name; - `CHANGELOG.md`: new file adding description for release 0.0.1; - `LICENSE`: copied from the `webview_flutter` package; - `README.md`: new file adding the standard platform implementation description; - `pubspec.yaml`: new file adding package meta-data for the `webview_flutter_android` package. * Direct copy of "android" folder. A one to one copy of the `webview_flutter/android` folder to `webview_flutter_android/` using the following command: ``` cp -R ./webview_flutter/android ./webview_flutter_android/ ``` * Direct copy of Android specific .dart files. Copied the Android specific .dart files over from the `./webview_flutter` package. Note that the `SurfaceAndroidWebView` class in the `./webview_flutter_android/lib/webview_surface_android.dart` file is copied directly (without modifactions) from the `./webview_flutter/lib/webview_flutter.dart` file. * Modify .dart code to work with platform_interface. Make sure the `AndroidWebView` and `SurfaceAndroidWebView` widgets extend the `WebViewPlatform` class from the `webview_flutter_platform_interface` package correctly by accepting an instance of the `JavascriptChannelRegistry` class. * Direct copy of the `webview_flutter/example` app. This commit makes a direct copy of the `webview_flutter/example` app to the `webview_flutter_android` package. After the copy the `example/ios` folder is removed as it doesn't serve a purpose in the Android specific package. Commands run where: ``` cp -R ./webview_flutter/example ./webview_flutter_android/ rm -rf ./webview_flutter_android/example/ios ``` * Update example to Android specific implementation. This commit updates the example App so it directly implements an Android specific implementation of the webview_flutter_platform_interface. * Update integration tests. Updated the existing integration tests (copied from webview_flutter package) so they work correctly with the implementation of the webview_flutter_android package. * Update webview_flutter_platform_interface dependency Updated the pubspec.yaml to depend on version 1.0.0 of the webview_flutter_platform_interface package instead of using a path reference (which is now possible since the platform interface package has now been published). Co-authored-by: BeMacized <[email protected]> * Use different bundle ID for Android example app. Make sure the `webview_flutter` and `webview_flutter_android` example apps use different application identifiers so that the CI doesn't run into problems. * Skip flaky integration_tests (issue 86757). * Exlude platform implementations from build all step. Make sure the webview_flutter_android and webview_flutter_wkwebview packages are excluded from the Build All plugins step as they will cause conflicts with the current implementation which is still part of the webview_flutter package. * Split helper classes from main example widget. Move the `WebView` and related `WebViewController` classes from the main.dart into a separate web_view.dart file. Co-authored-by: BeMacized <[email protected]>
- Loading branch information
Showing
57 changed files
with
5,128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Below is a list of people and organizations that have contributed | ||
# to the Flutter project. Names should be added to the list like so: | ||
# | ||
# Name/Organization <email address> | ||
|
||
Google Inc. | ||
The Chromium Authors | ||
German Saprykin <[email protected]> | ||
Benjamin Sauer <[email protected]> | ||
[email protected] | ||
Ali Bitek <[email protected]> | ||
Pol Batlló <[email protected]> | ||
Anatoly Pulyaevskiy | ||
Hayden Flinner <[email protected]> | ||
Stefano Rodriguez <[email protected]> | ||
Salvatore Giordano <[email protected]> | ||
Brian Armstrong <[email protected]> | ||
Paul DeMarco <[email protected]> | ||
Fabricio Nogueira <[email protected]> | ||
Simon Lightfoot <[email protected]> | ||
Ashton Thomas <[email protected]> | ||
Thomas Danner <[email protected]> | ||
Diego Velásquez <[email protected]> | ||
Hajime Nakamura <[email protected]> | ||
Tuyển Vũ Xuân <[email protected]> | ||
Miguel Ruivo <[email protected]> | ||
Sarthak Verma <[email protected]> | ||
Mike Diarmid <[email protected]> | ||
Invertase <[email protected]> | ||
Elliot Hesp <[email protected]> | ||
Vince Varga <[email protected]> | ||
Aawaz Gyawali <[email protected]> | ||
EUI Limited <[email protected]> | ||
Katarina Sheremet <[email protected]> | ||
Thomas Stockx <[email protected]> | ||
Sarbagya Dhaubanjar <[email protected]> | ||
Ozkan Eksi <[email protected]> | ||
Rishab Nayak <[email protected]> | ||
ko2ic <[email protected]> | ||
Jonathan Younger <[email protected]> | ||
Jose Sanchez <[email protected]> | ||
Debkanchan Samadder <[email protected]> | ||
Audrius Karosevicius <[email protected]> | ||
Lukasz Piliszczuk <[email protected]> | ||
SoundReply Solutions GmbH <[email protected]> | ||
Rafal Wachol <[email protected]> | ||
Pau Picas <[email protected]> | ||
Christian Weder <[email protected]> | ||
Alexandru Tuca <[email protected]> | ||
Christian Weder <[email protected]> | ||
Rhodes Davis Jr. <[email protected]> | ||
Luigi Agosti <[email protected]> | ||
Quentin Le Guennec <[email protected]> | ||
Koushik Ravikumar <[email protected]> | ||
Nissim Dsilva <[email protected]> | ||
Giancarlo Rocha <[email protected]> | ||
Ryo Miyake <[email protected]> | ||
Théo Champion <[email protected]> | ||
Kazuki Yamaguchi <[email protected]> | ||
Eitan Schwartz <[email protected]> | ||
Chris Rutkowski <[email protected]> | ||
Juan Alvarez <[email protected]> | ||
Aleksandr Yurkovskiy <[email protected]> | ||
Anton Borries <[email protected]> | ||
Alex Li <[email protected]> | ||
Rahul Raj <[email protected]> | ||
Maurits van Beusekom <[email protected]> | ||
|
4 changes: 4 additions & 0 deletions
4
packages/webview_flutter/webview_flutter_android/CHANGELOG.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
## 2.0.13 | ||
|
||
* Extract Android implementation from `webview_flutter`. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
Copyright 2013 The Flutter Authors. All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without modification, | ||
are permitted provided that the following conditions are met: | ||
|
||
* Redistributions of source code must retain the above copyright | ||
notice, this list of conditions and the following disclaimer. | ||
* Redistributions in binary form must reproduce the above | ||
copyright notice, this list of conditions and the following | ||
disclaimer in the documentation and/or other materials provided | ||
with the distribution. | ||
* Neither the name of Google Inc. nor the names of its | ||
contributors may be used to endorse or promote products derived | ||
from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|
12 changes: 12 additions & 0 deletions
12
packages/webview_flutter/webview_flutter_android/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# webview\_flutter\_android | ||
|
||
The Android implementation of [`webview_flutter`][1]. | ||
|
||
## Usage | ||
|
||
This package is [endorsed][2], which means you can simply use `webview_flutter` | ||
normally. This package will be automatically included in your app when you do. | ||
|
||
[1]: https://pub.dev/packages/webview_flutter | ||
[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin | ||
|
57 changes: 57 additions & 0 deletions
57
packages/webview_flutter/webview_flutter_android/android/build.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
group 'io.flutter.plugins.webviewflutter' | ||
version '1.0-SNAPSHOT' | ||
|
||
buildscript { | ||
repositories { | ||
google() | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
classpath 'com.android.tools.build:gradle:3.3.0' | ||
} | ||
} | ||
|
||
rootProject.allprojects { | ||
repositories { | ||
google() | ||
mavenCentral() | ||
} | ||
} | ||
|
||
apply plugin: 'com.android.library' | ||
|
||
android { | ||
compileSdkVersion 29 | ||
|
||
defaultConfig { | ||
minSdkVersion 19 | ||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | ||
} | ||
|
||
lintOptions { | ||
disable 'InvalidPackage' | ||
disable 'GradleDependency' | ||
} | ||
|
||
dependencies { | ||
implementation 'androidx.annotation:annotation:1.0.0' | ||
implementation 'androidx.webkit:webkit:1.0.0' | ||
testImplementation 'junit:junit:4.12' | ||
testImplementation 'org.mockito:mockito-inline:3.11.1' | ||
testImplementation 'androidx.test:core:1.3.0' | ||
} | ||
|
||
|
||
testOptions { | ||
unitTests.includeAndroidResources = true | ||
unitTests.returnDefaultValues = true | ||
unitTests.all { | ||
testLogging { | ||
events "passed", "skipped", "failed", "standardOut", "standardError" | ||
outputs.upToDateWhen {false} | ||
showStandardStreams = true | ||
} | ||
} | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
packages/webview_flutter/webview_flutter_android/android/settings.gradle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
rootProject.name = 'webview_flutter' |
2 changes: 2 additions & 0 deletions
2
packages/webview_flutter/webview_flutter_android/android/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<manifest package="io.flutter.plugins.webviewflutter"> | ||
</manifest> |
147 changes: 147 additions & 0 deletions
147
...android/android/src/main/java/io/flutter/plugins/webviewflutter/DisplayListenerProxy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.webviewflutter; | ||
|
||
import static android.hardware.display.DisplayManager.DisplayListener; | ||
|
||
import android.annotation.TargetApi; | ||
import android.hardware.display.DisplayManager; | ||
import android.os.Build; | ||
import android.util.Log; | ||
import java.lang.reflect.Field; | ||
import java.util.ArrayList; | ||
|
||
/** | ||
* Works around an Android WebView bug by filtering some DisplayListener invocations. | ||
* | ||
* <p>Older Android WebView versions had assumed that when {@link DisplayListener#onDisplayChanged} | ||
* is invoked, the display ID it is provided is of a valid display. However it turns out that when a | ||
* display is removed Android may call onDisplayChanged with the ID of the removed display, in this | ||
* case the Android WebView code tries to fetch and use the display with this ID and crashes with an | ||
* NPE. | ||
* | ||
* <p>This issue was fixed in the Android WebView code in | ||
* https://chromium-review.googlesource.com/517913 which is available starting WebView version | ||
* 58.0.3029.125 however older webviews in the wild still have this issue. | ||
* | ||
* <p>Since Flutter removes virtual displays whenever a platform view is resized the webview crash | ||
* is more likely to happen than other apps. And users were reporting this issue see: | ||
* https://github.com/flutter/flutter/issues/30420 | ||
* | ||
* <p>This class works around the webview bug by unregistering the WebView's DisplayListener, and | ||
* instead registering its own DisplayListener which delegates the callbacks to the WebView's | ||
* listener unless it's a onDisplayChanged for an invalid display. | ||
* | ||
* <p>I did not find a clean way to get a handle of the WebView's DisplayListener so I'm using | ||
* reflection to fetch all registered listeners before and after initializing a webview. In the | ||
* first initialization of a webview within the process the difference between the lists is the | ||
* webview's display listener. | ||
*/ | ||
@TargetApi(Build.VERSION_CODES.KITKAT) | ||
class DisplayListenerProxy { | ||
private static final String TAG = "DisplayListenerProxy"; | ||
|
||
private ArrayList<DisplayListener> listenersBeforeWebView; | ||
|
||
/** Should be called prior to the webview's initialization. */ | ||
void onPreWebViewInitialization(DisplayManager displayManager) { | ||
listenersBeforeWebView = yoinkDisplayListeners(displayManager); | ||
} | ||
|
||
/** Should be called after the webview's initialization. */ | ||
void onPostWebViewInitialization(final DisplayManager displayManager) { | ||
final ArrayList<DisplayListener> webViewListeners = yoinkDisplayListeners(displayManager); | ||
// We recorded the list of listeners prior to initializing webview, any new listeners we see | ||
// after initializing the webview are listeners added by the webview. | ||
webViewListeners.removeAll(listenersBeforeWebView); | ||
|
||
if (webViewListeners.isEmpty()) { | ||
// The Android WebView registers a single display listener per process (even if there | ||
// are multiple WebView instances) so this list is expected to be non-empty only the | ||
// first time a webview is initialized. | ||
// Note that in an add2app scenario if the application had instantiated a non Flutter | ||
// WebView prior to instantiating the Flutter WebView we are not able to get a reference | ||
// to the WebView's display listener and can't work around the bug. | ||
// | ||
// This means that webview resizes in add2app Flutter apps with a non Flutter WebView | ||
// running on a system with a webview prior to 58.0.3029.125 may crash (the Android's | ||
// behavior seems to be racy so it doesn't always happen). | ||
return; | ||
} | ||
|
||
for (DisplayListener webViewListener : webViewListeners) { | ||
// Note that while DisplayManager.unregisterDisplayListener throws when given an | ||
// unregistered listener, this isn't an issue as the WebView code never calls | ||
// unregisterDisplayListener. | ||
displayManager.unregisterDisplayListener(webViewListener); | ||
|
||
// We never explicitly unregister this listener as the webview's listener is never | ||
// unregistered (it's released when the process is terminated). | ||
displayManager.registerDisplayListener( | ||
new DisplayListener() { | ||
@Override | ||
public void onDisplayAdded(int displayId) { | ||
for (DisplayListener webViewListener : webViewListeners) { | ||
webViewListener.onDisplayAdded(displayId); | ||
} | ||
} | ||
|
||
@Override | ||
public void onDisplayRemoved(int displayId) { | ||
for (DisplayListener webViewListener : webViewListeners) { | ||
webViewListener.onDisplayRemoved(displayId); | ||
} | ||
} | ||
|
||
@Override | ||
public void onDisplayChanged(int displayId) { | ||
if (displayManager.getDisplay(displayId) == null) { | ||
return; | ||
} | ||
for (DisplayListener webViewListener : webViewListeners) { | ||
webViewListener.onDisplayChanged(displayId); | ||
} | ||
} | ||
}, | ||
null); | ||
} | ||
} | ||
|
||
@SuppressWarnings({"unchecked", "PrivateApi"}) | ||
private static ArrayList<DisplayListener> yoinkDisplayListeners(DisplayManager displayManager) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | ||
// We cannot use reflection on Android P, but it shouldn't matter as it shipped | ||
// with WebView 66.0.3359.158 and the WebView version the bug this code is working around was | ||
// fixed in 61.0.3116.0. | ||
return new ArrayList<>(); | ||
} | ||
try { | ||
Field displayManagerGlobalField = DisplayManager.class.getDeclaredField("mGlobal"); | ||
displayManagerGlobalField.setAccessible(true); | ||
Object displayManagerGlobal = displayManagerGlobalField.get(displayManager); | ||
Field displayListenersField = | ||
displayManagerGlobal.getClass().getDeclaredField("mDisplayListeners"); | ||
displayListenersField.setAccessible(true); | ||
ArrayList<Object> delegates = | ||
(ArrayList<Object>) displayListenersField.get(displayManagerGlobal); | ||
|
||
Field listenerField = null; | ||
ArrayList<DisplayManager.DisplayListener> listeners = new ArrayList<>(); | ||
for (Object delegate : delegates) { | ||
if (listenerField == null) { | ||
listenerField = delegate.getClass().getField("mListener"); | ||
listenerField.setAccessible(true); | ||
} | ||
DisplayManager.DisplayListener listener = | ||
(DisplayManager.DisplayListener) listenerField.get(delegate); | ||
listeners.add(listener); | ||
} | ||
return listeners; | ||
} catch (NoSuchFieldException | IllegalAccessException e) { | ||
Log.w(TAG, "Could not extract WebView's display listeners. " + e); | ||
return new ArrayList<>(); | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...android/android/src/main/java/io/flutter/plugins/webviewflutter/FlutterCookieManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.webviewflutter; | ||
|
||
import android.os.Build; | ||
import android.os.Build.VERSION_CODES; | ||
import android.webkit.CookieManager; | ||
import android.webkit.ValueCallback; | ||
import io.flutter.plugin.common.BinaryMessenger; | ||
import io.flutter.plugin.common.MethodCall; | ||
import io.flutter.plugin.common.MethodChannel; | ||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; | ||
import io.flutter.plugin.common.MethodChannel.Result; | ||
|
||
class FlutterCookieManager implements MethodCallHandler { | ||
private final MethodChannel methodChannel; | ||
|
||
FlutterCookieManager(BinaryMessenger messenger) { | ||
methodChannel = new MethodChannel(messenger, "plugins.flutter.io/cookie_manager"); | ||
methodChannel.setMethodCallHandler(this); | ||
} | ||
|
||
@Override | ||
public void onMethodCall(MethodCall methodCall, Result result) { | ||
switch (methodCall.method) { | ||
case "clearCookies": | ||
clearCookies(result); | ||
break; | ||
default: | ||
result.notImplemented(); | ||
} | ||
} | ||
|
||
void dispose() { | ||
methodChannel.setMethodCallHandler(null); | ||
} | ||
|
||
private static void clearCookies(final Result result) { | ||
CookieManager cookieManager = CookieManager.getInstance(); | ||
final boolean hasCookies = cookieManager.hasCookies(); | ||
if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { | ||
cookieManager.removeAllCookies( | ||
new ValueCallback<Boolean>() { | ||
@Override | ||
public void onReceiveValue(Boolean value) { | ||
result.success(hasCookies); | ||
} | ||
}); | ||
} else { | ||
cookieManager.removeAllCookie(); | ||
result.success(hasCookies); | ||
} | ||
} | ||
} |
Oops, something went wrong.