Skip to content

Commit

Permalink
[webview_flutter] Android implementation of loadFlutterAsset method. (
Browse files Browse the repository at this point in the history
  • Loading branch information
mvanbeusekom authored Dec 7, 2021
1 parent 7d9cc84 commit 17f95e9
Show file tree
Hide file tree
Showing 24 changed files with 775 additions and 10 deletions.
4 changes: 4 additions & 0 deletions packages/webview_flutter/webview_flutter_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.6.0

* Adds implementation of the `loadFlutterAsset` method from the platform interface.

## 2.5.0

* Adds an option to set the background color of the webview.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,4 @@ android {
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// 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.content.res.AssetManager;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.PluginRegistry;
import java.io.IOException;

/** Provides access to the assets registered as part of the App bundle. */
abstract class FlutterAssetManager {
final AssetManager assetManager;

/**
* Constructs a new instance of the {@link FlutterAssetManager}.
*
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within the
* App bundle.
*/
public FlutterAssetManager(AssetManager assetManager) {
this.assetManager = assetManager;
}

/**
* Gets the relative file path to the Flutter asset with the given name, including the file's
* extension, e.g., "myImage.jpg".
*
* <p>The returned file path is relative to the Android app's standard asset's directory.
* Therefore, the returned path is appropriate to pass to Android's AssetManager, but the path is
* not appropriate to load as an absolute path.
*/
abstract String getAssetFilePathByName(String name);

/**
* Returns a String array of all the assets at the given path.
*
* @param path A relative path within the assets, i.e., "docs/home.html". This value cannot be
* null.
* @return String[] Array of strings, one for each asset. These file names are relative to 'path'.
* This value may be null.
* @throws IOException Throws an IOException in case I/O operations were interrupted.
*/
public String[] list(@NonNull String path) throws IOException {
return assetManager.list(path);
}

/**
* Provides access to assets using the {@link PluginRegistry.Registrar} for looking up file paths
* to Flutter assets.
*
* @deprecated The {@link RegistrarFlutterAssetManager} is for Flutter's v1 embedding. For
* instructions on migrating a plugin from Flutter's v1 Android embedding to v2, visit
* http://flutter.dev/go/android-plugin-migration
*/
@Deprecated
static class RegistrarFlutterAssetManager extends FlutterAssetManager {
final PluginRegistry.Registrar registrar;

/**
* Constructs a new instance of the {@link RegistrarFlutterAssetManager}.
*
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within
* the App bundle.
* @param registrar Instance of {@link io.flutter.plugin.common.PluginRegistry.Registrar} used
* to look up file paths to assets registered by Flutter.
*/
RegistrarFlutterAssetManager(AssetManager assetManager, PluginRegistry.Registrar registrar) {
super(assetManager);
this.registrar = registrar;
}

@Override
public String getAssetFilePathByName(String name) {
return registrar.lookupKeyForAsset(name);
}
}

/**
* Provides access to assets using the {@link FlutterPlugin.FlutterAssets} for looking up file
* paths to Flutter assets.
*/
static class PluginBindingFlutterAssetManager extends FlutterAssetManager {
final FlutterPlugin.FlutterAssets flutterAssets;

/**
* Constructs a new instance of the {@link PluginBindingFlutterAssetManager}.
*
* @param assetManager Instance of Android's {@link AssetManager} used to access assets within
* the App bundle.
* @param flutterAssets Instance of {@link
* io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterAssets} used to look up file
* paths to assets registered by Flutter.
*/
PluginBindingFlutterAssetManager(
AssetManager assetManager, FlutterPlugin.FlutterAssets flutterAssets) {
super(assetManager);
this.flutterAssets = flutterAssets;
}

@Override
public String getAssetFilePathByName(String name) {
return flutterAssets.getAssetFilePathByName(name);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.webkit.WebView;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Host api implementation for {@link WebView}.
*
* <p>Handles creating {@link WebView}s that intercommunicate with a paired Dart object.
*/
public class FlutterAssetManagerHostApiImpl implements FlutterAssetManagerHostApi {
final FlutterAssetManager flutterAssetManager;

/** Constructs a new instance of {@link FlutterAssetManagerHostApiImpl}. */
public FlutterAssetManagerHostApiImpl(FlutterAssetManager flutterAssetManager) {
this.flutterAssetManager = flutterAssetManager;
}

@Override
public List<String> list(String path) {
try {
String[] paths = flutterAssetManager.list(path);

if (paths == null) {
return new ArrayList<>();
}

return Arrays.asList(paths);
} catch (IOException ex) {
throw new RuntimeException(ex.getMessage());
}
}

@Override
public String getAssetFilePathByName(String name) {
return flutterAssetManager.getAssetFilePathByName(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** Generated class from Pigeon. */
Expand Down Expand Up @@ -1915,6 +1916,84 @@ static void setup(BinaryMessenger binaryMessenger, WebChromeClientHostApi api) {
}
}

private static class FlutterAssetManagerHostApiCodec extends StandardMessageCodec {
public static final FlutterAssetManagerHostApiCodec INSTANCE =
new FlutterAssetManagerHostApiCodec();

private FlutterAssetManagerHostApiCodec() {}
}

/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface FlutterAssetManagerHostApi {
List<String> list(String path);

String getAssetFilePathByName(String name);

/** The codec used by FlutterAssetManagerHostApi. */
static MessageCodec<Object> getCodec() {
return FlutterAssetManagerHostApiCodec.INSTANCE;
}

/**
* Sets up an instance of `FlutterAssetManagerHostApi` to handle messages through the
* `binaryMessenger`.
*/
static void setup(BinaryMessenger binaryMessenger, FlutterAssetManagerHostApi api) {
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.FlutterAssetManagerHostApi.list", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
String pathArg = (String) args.get(0);
if (pathArg == null) {
throw new NullPointerException("pathArg unexpectedly null.");
}
List<String> output = api.list(pathArg);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger,
"dev.flutter.pigeon.FlutterAssetManagerHostApi.getAssetFilePathByName",
getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
Map<String, Object> wrapped = new HashMap<>();
try {
ArrayList<Object> args = (ArrayList<Object>) message;
String nameArg = (String) args.get(0);
if (nameArg == null) {
throw new NullPointerException("nameArg unexpectedly null.");
}
String output = api.getAssetFilePathByName(nameArg);
wrapped.put("result", output);
} catch (Error | RuntimeException exception) {
wrapped.put("error", wrapError(exception));
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
}
}

private static class WebChromeClientFlutterApiCodec extends StandardMessageCodec {
public static final WebChromeClientFlutterApiCodec INSTANCE =
new WebChromeClientFlutterApiCodec();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformViewRegistry;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.DownloadListenerHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.FlutterAssetManagerHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.JavaScriptChannelHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebChromeClientHostApi;
import io.flutter.plugins.webviewflutter.GeneratedAndroidWebView.WebSettingsHostApi;
Expand Down Expand Up @@ -61,15 +62,18 @@ public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registra
registrar.messenger(),
registrar.platformViewRegistry(),
registrar.activity(),
registrar.view());
registrar.view(),
new FlutterAssetManager.RegistrarFlutterAssetManager(
registrar.context().getAssets(), registrar));
new FlutterCookieManager(registrar.messenger());
}

private void setUp(
BinaryMessenger binaryMessenger,
PlatformViewRegistry viewRegistry,
Context context,
View containerView) {
View containerView,
FlutterAssetManager flutterAssetManager) {
new FlutterCookieManager(binaryMessenger);

InstanceManager instanceManager = new InstanceManager();
Expand Down Expand Up @@ -111,6 +115,8 @@ private void setUp(
binaryMessenger,
new WebSettingsHostApiImpl(
instanceManager, new WebSettingsHostApiImpl.WebSettingsCreator()));
FlutterAssetManagerHostApi.setup(
binaryMessenger, new FlutterAssetManagerHostApiImpl(flutterAssetManager));
}

@Override
Expand All @@ -120,7 +126,9 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
binding.getBinaryMessenger(),
binding.getPlatformViewRegistry(),
binding.getApplicationContext(),
null);
null,
new FlutterAssetManager.PluginBindingFlutterAssetManager(
binding.getApplicationContext().getAssets(), binding.getFlutterAssets()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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 org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

public class FlutterAssetManagerHostApiImplTest {
@Mock FlutterAssetManager mockFlutterAssetManager;

FlutterAssetManagerHostApiImpl testFlutterAssetManagerHostApiImpl;

@Before
public void setUp() {
mockFlutterAssetManager = mock(FlutterAssetManager.class);

testFlutterAssetManagerHostApiImpl =
new FlutterAssetManagerHostApiImpl(mockFlutterAssetManager);
}

@Test
public void list() {
try {
when(mockFlutterAssetManager.list("test/path"))
.thenReturn(new String[] {"index.html", "styles.css"});
List<String> actualFilePaths = testFlutterAssetManagerHostApiImpl.list("test/path");
verify(mockFlutterAssetManager).list("test/path");
assertArrayEquals(new String[] {"index.html", "styles.css"}, actualFilePaths.toArray());
} catch (IOException ex) {
fail();
}
}

@Test
public void list_returns_empty_list_when_no_results() {
try {
when(mockFlutterAssetManager.list("test/path")).thenReturn(null);
List<String> actualFilePaths = testFlutterAssetManagerHostApiImpl.list("test/path");
verify(mockFlutterAssetManager).list("test/path");
assertArrayEquals(new String[] {}, actualFilePaths.toArray());
} catch (IOException ex) {
fail();
}
}

@Test(expected = RuntimeException.class)
public void list_should_convert_io_exception_to_runtime_exception() {
try {
when(mockFlutterAssetManager.list("test/path")).thenThrow(new IOException());
testFlutterAssetManagerHostApiImpl.list("test/path");
} catch (IOException ex) {
fail();
}
}

@Test
public void getAssetFilePathByName() {
when(mockFlutterAssetManager.getAssetFilePathByName("index.html"))
.thenReturn("flutter_assets/index.html");
String filePath = testFlutterAssetManagerHostApiImpl.getAssetFilePathByName("index.html");
verify(mockFlutterAssetManager).getAssetFilePathByName("index.html");
assertEquals("flutter_assets/index.html", filePath);
}
}
Loading

0 comments on commit 17f95e9

Please sign in to comment.