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

Commit 17f95e9

Browse files
authored
[webview_flutter] Android implementation of loadFlutterAsset method. (#4581)
1 parent 7d9cc84 commit 17f95e9

24 files changed

+775
-10
lines changed

packages/webview_flutter/webview_flutter_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.6.0
2+
3+
* Adds implementation of the `loadFlutterAsset` method from the platform interface.
4+
15
## 2.5.0
26

37
* Adds an option to set the background color of the webview.

packages/webview_flutter/webview_flutter_android/android/build.gradle

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,4 @@ android {
5858
}
5959
}
6060
}
61-
compileOptions {
62-
sourceCompatibility JavaVersion.VERSION_1_8
63-
targetCompatibility JavaVersion.VERSION_1_8
64-
}
6561
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.webviewflutter;
6+
7+
import android.content.res.AssetManager;
8+
import androidx.annotation.NonNull;
9+
import io.flutter.embedding.engine.plugins.FlutterPlugin;
10+
import io.flutter.plugin.common.PluginRegistry;
11+
import java.io.IOException;
12+
13+
/** Provides access to the assets registered as part of the App bundle. */
14+
abstract class FlutterAssetManager {
15+
final AssetManager assetManager;
16+
17+
/**
18+
* Constructs a new instance of the {@link FlutterAssetManager}.
19+
*
20+
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within the
21+
* App bundle.
22+
*/
23+
public FlutterAssetManager(AssetManager assetManager) {
24+
this.assetManager = assetManager;
25+
}
26+
27+
/**
28+
* Gets the relative file path to the Flutter asset with the given name, including the file's
29+
* extension, e.g., "myImage.jpg".
30+
*
31+
* <p>The returned file path is relative to the Android app's standard asset's directory.
32+
* Therefore, the returned path is appropriate to pass to Android's AssetManager, but the path is
33+
* not appropriate to load as an absolute path.
34+
*/
35+
abstract String getAssetFilePathByName(String name);
36+
37+
/**
38+
* Returns a String array of all the assets at the given path.
39+
*
40+
* @param path A relative path within the assets, i.e., "docs/home.html". This value cannot be
41+
* null.
42+
* @return String[] Array of strings, one for each asset. These file names are relative to 'path'.
43+
* This value may be null.
44+
* @throws IOException Throws an IOException in case I/O operations were interrupted.
45+
*/
46+
public String[] list(@NonNull String path) throws IOException {
47+
return assetManager.list(path);
48+
}
49+
50+
/**
51+
* Provides access to assets using the {@link PluginRegistry.Registrar} for looking up file paths
52+
* to Flutter assets.
53+
*
54+
* @deprecated The {@link RegistrarFlutterAssetManager} is for Flutter's v1 embedding. For
55+
* instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
56+
* http://flutter.dev/go/android-plugin-migration
57+
*/
58+
@Deprecated
59+
static class RegistrarFlutterAssetManager extends FlutterAssetManager {
60+
final PluginRegistry.Registrar registrar;
61+
62+
/**
63+
* Constructs a new instance of the {@link RegistrarFlutterAssetManager}.
64+
*
65+
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within
66+
* the App bundle.
67+
* @param registrar Instance of {@link io.flutter.plugin.common.PluginRegistry.Registrar} used
68+
* to look up file paths to assets registered by Flutter.
69+
*/
70+
RegistrarFlutterAssetManager(AssetManager assetManager, PluginRegistry.Registrar registrar) {
71+
super(assetManager);
72+
this.registrar = registrar;
73+
}
74+
75+
@Override
76+
public String getAssetFilePathByName(String name) {
77+
return registrar.lookupKeyForAsset(name);
78+
}
79+
}
80+
81+
/**
82+
* Provides access to assets using the {@link FlutterPlugin.FlutterAssets} for looking up file
83+
* paths to Flutter assets.
84+
*/
85+
static class PluginBindingFlutterAssetManager extends FlutterAssetManager {
86+
final FlutterPlugin.FlutterAssets flutterAssets;
87+
88+
/**
89+
* Constructs a new instance of the {@link PluginBindingFlutterAssetManager}.
90+
*
91+
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within
92+
* the App bundle.
93+
* @param flutterAssets Instance of {@link
94+
* io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterAssets} used to look up file
95+
* paths to assets registered by Flutter.
96+
*/
97+
PluginBindingFlutterAssetManager(
98+
AssetManager assetManager, FlutterPlugin.FlutterAssets flutterAssets) {
99+
super(assetManager);
100+
this.flutterAssets = flutterAssets;
101+
}
102+
103+
@Override
104+
public String getAssetFilePathByName(String name) {
105+
return flutterAssets.getAssetFilePathByName(name);
106+
}
107+
}
108+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.webviewflutter;
6+
7+
import android.webkit.WebView;
8+
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
9+
import java.io.IOException;
10+
import java.util.ArrayList;
11+
import java.util.Arrays;
12+
import java.util.List;
13+
14+
/**
15+
* Host api implementation for {@link WebView}.
16+
*
17+
* <p>Handles creating {@link WebView}s that intercommunicate with a paired Dart object.
18+
*/
19+
public class FlutterAssetManagerHostApiImpl implements FlutterAssetManagerHostApi {
20+
final FlutterAssetManager flutterAssetManager;
21+
22+
/** Constructs a new instance of {@link FlutterAssetManagerHostApiImpl}. */
23+
public FlutterAssetManagerHostApiImpl(FlutterAssetManager flutterAssetManager) {
24+
this.flutterAssetManager = flutterAssetManager;
25+
}
26+
27+
@Override
28+
public List<String> list(String path) {
29+
try {
30+
String[] paths = flutterAssetManager.list(path);
31+
32+
if (paths == null) {
33+
return new ArrayList<>();
34+
}
35+
36+
return Arrays.asList(paths);
37+
} catch (IOException ex) {
38+
throw new RuntimeException(ex.getMessage());
39+
}
40+
}
41+
42+
@Override
43+
public String getAssetFilePathByName(String name) {
44+
return flutterAssetManager.getAssetFilePathByName(name);
45+
}
46+
}

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/GeneratedAndroidWebView.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.ArrayList;
1717
import java.util.Arrays;
1818
import java.util.HashMap;
19+
import java.util.List;
1920
import java.util.Map;
2021

2122
/** Generated class from Pigeon. */
@@ -1915,6 +1916,84 @@ static void setup(BinaryMessenger binaryMessenger, WebChromeClientHostApi api) {
19151916
}
19161917
}
19171918

1919+
private static class FlutterAssetManagerHostApiCodec extends StandardMessageCodec {
1920+
public static final FlutterAssetManagerHostApiCodec INSTANCE =
1921+
new FlutterAssetManagerHostApiCodec();
1922+
1923+
private FlutterAssetManagerHostApiCodec() {}
1924+
}
1925+
1926+
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
1927+
public interface FlutterAssetManagerHostApi {
1928+
List<String> list(String path);
1929+
1930+
String getAssetFilePathByName(String name);
1931+
1932+
/** The codec used by FlutterAssetManagerHostApi. */
1933+
static MessageCodec<Object> getCodec() {
1934+
return FlutterAssetManagerHostApiCodec.INSTANCE;
1935+
}
1936+
1937+
/**
1938+
* Sets up an instance of `FlutterAssetManagerHostApi` to handle messages through the
1939+
* `binaryMessenger`.
1940+
*/
1941+
static void setup(BinaryMessenger binaryMessenger, FlutterAssetManagerHostApi api) {
1942+
{
1943+
BasicMessageChannel<Object> channel =
1944+
new BasicMessageChannel<>(
1945+
binaryMessenger, "dev.flutter.pigeon.FlutterAssetManagerHostApi.list", getCodec());
1946+
if (api != null) {
1947+
channel.setMessageHandler(
1948+
(message, reply) -> {
1949+
Map<String, Object> wrapped = new HashMap<>();
1950+
try {
1951+
ArrayList<Object> args = (ArrayList<Object>) message;
1952+
String pathArg = (String) args.get(0);
1953+
if (pathArg == null) {
1954+
throw new NullPointerException("pathArg unexpectedly null.");
1955+
}
1956+
List<String> output = api.list(pathArg);
1957+
wrapped.put("result", output);
1958+
} catch (Error | RuntimeException exception) {
1959+
wrapped.put("error", wrapError(exception));
1960+
}
1961+
reply.reply(wrapped);
1962+
});
1963+
} else {
1964+
channel.setMessageHandler(null);
1965+
}
1966+
}
1967+
{
1968+
BasicMessageChannel<Object> channel =
1969+
new BasicMessageChannel<>(
1970+
binaryMessenger,
1971+
"dev.flutter.pigeon.FlutterAssetManagerHostApi.getAssetFilePathByName",
1972+
getCodec());
1973+
if (api != null) {
1974+
channel.setMessageHandler(
1975+
(message, reply) -> {
1976+
Map<String, Object> wrapped = new HashMap<>();
1977+
try {
1978+
ArrayList<Object> args = (ArrayList<Object>) message;
1979+
String nameArg = (String) args.get(0);
1980+
if (nameArg == null) {
1981+
throw new NullPointerException("nameArg unexpectedly null.");
1982+
}
1983+
String output = api.getAssetFilePathByName(nameArg);
1984+
wrapped.put("result", output);
1985+
} catch (Error | RuntimeException exception) {
1986+
wrapped.put("error", wrapError(exception));
1987+
}
1988+
reply.reply(wrapped);
1989+
});
1990+
} else {
1991+
channel.setMessageHandler(null);
1992+
}
1993+
}
1994+
}
1995+
}
1996+
19181997
private static class WebChromeClientFlutterApiCodec extends StandardMessageCodec {
19191998
public static final WebChromeClientFlutterApiCodec INSTANCE =
19201999
new WebChromeClientFlutterApiCodec();

packages/webview_flutter/webview_flutter_android/android/src/main/java/io/flutter/plugins/webviewflutter/WebViewFlutterPlugin.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import io.flutter.plugin.common.BinaryMessenger;
1515
import io.flutter.plugin.platform.PlatformViewRegistry;
1616
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
17+
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
1718
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
1819
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi;
1920
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi;
@@ -61,15 +62,18 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra
6162
registrar.messenger(),
6263
registrar.platformViewRegistry(),
6364
registrar.activity(),
64-
registrar.view());
65+
registrar.view(),
66+
new FlutterAssetManager.RegistrarFlutterAssetManager(
67+
registrar.context().getAssets(), registrar));
6568
new FlutterCookieManager(registrar.messenger());
6669
}
6770

6871
private void setUp(
6972
BinaryMessenger binaryMessenger,
7073
PlatformViewRegistry viewRegistry,
7174
Context context,
72-
View containerView) {
75+
View containerView,
76+
FlutterAssetManager flutterAssetManager) {
7377
new FlutterCookieManager(binaryMessenger);
7478

7579
InstanceManager instanceManager = new InstanceManager();
@@ -111,6 +115,8 @@ private void setUp(
111115
binaryMessenger,
112116
new WebSettingsHostApiImpl(
113117
instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator()));
118+
FlutterAssetManagerHostApi.setup(
119+
binaryMessenger, new FlutterAssetManagerHostApiImpl(flutterAssetManager));
114120
}
115121

116122
@Override
@@ -120,7 +126,9 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
120126
binding.getBinaryMessenger(),
121127
binding.getPlatformViewRegistry(),
122128
binding.getApplicationContext(),
123-
null);
129+
null,
130+
new FlutterAssetManager.PluginBindingFlutterAssetManager(
131+
binding.getApplicationContext().getAssets(), binding.getFlutterAssets()));
124132
}
125133

126134
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugins.webviewflutter;
6+
7+
import static org.junit.Assert.assertArrayEquals;
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.fail;
10+
import static org.mockito.Mockito.mock;
11+
import static org.mockito.Mockito.verify;
12+
import static org.mockito.Mockito.when;
13+
14+
import java.io.IOException;
15+
import java.util.List;
16+
import org.junit.Before;
17+
import org.junit.Test;
18+
import org.mockito.Mock;
19+
20+
public class FlutterAssetManagerHostApiImplTest {
21+
@Mock FlutterAssetManager mockFlutterAssetManager;
22+
23+
FlutterAssetManagerHostApiImpl testFlutterAssetManagerHostApiImpl;
24+
25+
@Before
26+
public void setUp() {
27+
mockFlutterAssetManager = mock(FlutterAssetManager.class);
28+
29+
testFlutterAssetManagerHostApiImpl =
30+
new FlutterAssetManagerHostApiImpl(mockFlutterAssetManager);
31+
}
32+
33+
@Test
34+
public void list() {
35+
try {
36+
when(mockFlutterAssetManager.list("test/path"))
37+
.thenReturn(new String[] {"index.html", "styles.css"});
38+
List<String> actualFilePaths = testFlutterAssetManagerHostApiImpl.list("test/path");
39+
verify(mockFlutterAssetManager).list("test/path");
40+
assertArrayEquals(new String[] {"index.html", "styles.css"}, actualFilePaths.toArray());
41+
} catch (IOException ex) {
42+
fail();
43+
}
44+
}
45+
46+
@Test
47+
public void list_returns_empty_list_when_no_results() {
48+
try {
49+
when(mockFlutterAssetManager.list("test/path")).thenReturn(null);
50+
List<String> actualFilePaths = testFlutterAssetManagerHostApiImpl.list("test/path");
51+
verify(mockFlutterAssetManager).list("test/path");
52+
assertArrayEquals(new String[] {}, actualFilePaths.toArray());
53+
} catch (IOException ex) {
54+
fail();
55+
}
56+
}
57+
58+
@Test(expected = RuntimeException.class)
59+
public void list_should_convert_io_exception_to_runtime_exception() {
60+
try {
61+
when(mockFlutterAssetManager.list("test/path")).thenThrow(new IOException());
62+
testFlutterAssetManagerHostApiImpl.list("test/path");
63+
} catch (IOException ex) {
64+
fail();
65+
}
66+
}
67+
68+
@Test
69+
public void getAssetFilePathByName() {
70+
when(mockFlutterAssetManager.getAssetFilePathByName("index.html"))
71+
.thenReturn("flutter_assets/index.html");
72+
String filePath = testFlutterAssetManagerHostApiImpl.getAssetFilePathByName("index.html");
73+
verify(mockFlutterAssetManager).getAssetFilePathByName("index.html");
74+
assertEquals("flutter_assets/index.html", filePath);
75+
}
76+
}

0 commit comments

Comments
 (0)