未验证 提交 e19ee72f 编写于 作者: M Matt Carroll 提交者: GitHub

Expose asset lookup from plugin binding. (#42019) (#13743)

上级 c9afadcc
......@@ -422,6 +422,7 @@ action("robolectric_tests") {
"test/io/flutter/embedding/engine/FlutterEngineCacheTest.java",
"test/io/flutter/embedding/engine/FlutterEngineTest.java",
"test/io/flutter/embedding/engine/FlutterJNITest.java",
"test/io/flutter/embedding/engine/PluginComponentTest.java",
"test/io/flutter/embedding/engine/RenderingComponentTest.java",
"test/io/flutter/embedding/engine/dart/DartExecutorTest.java",
"test/io/flutter/embedding/engine/plugins/shim/ShimPluginRegistryTest.java",
......
......@@ -207,7 +207,8 @@ public class FlutterEngine {
this.pluginRegistry = new FlutterEnginePluginRegistry(
context.getApplicationContext(),
this
this,
flutterLoader
);
if (automaticallyRegisterPlugins) {
......
......@@ -21,6 +21,7 @@ import java.util.Map;
import java.util.Set;
import io.flutter.Log;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.PluginRegistry;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
......@@ -90,7 +91,8 @@ class FlutterEnginePluginRegistry implements PluginRegistry,
FlutterEnginePluginRegistry(
@NonNull Context appContext,
@NonNull FlutterEngine flutterEngine
@NonNull FlutterEngine flutterEngine,
@NonNull FlutterLoader flutterLoader
) {
this.flutterEngine = flutterEngine;
pluginBinding = new FlutterPlugin.FlutterPluginBinding(
......@@ -98,7 +100,8 @@ class FlutterEnginePluginRegistry implements PluginRegistry,
flutterEngine,
flutterEngine.getDartExecutor(),
flutterEngine.getRenderer(),
flutterEngine.getPlatformViewsController().getRegistry()
flutterEngine.getPlatformViewsController().getRegistry(),
new DefaultFlutterAssets(flutterLoader)
);
}
......@@ -532,6 +535,30 @@ class FlutterEnginePluginRegistry implements PluginRegistry,
}
//----- End ContentProviderControlSurface -----
private static class DefaultFlutterAssets implements FlutterPlugin.FlutterAssets {
final FlutterLoader flutterLoader;
private DefaultFlutterAssets(@NonNull FlutterLoader flutterLoader) {
this.flutterLoader = flutterLoader;
}
public String getAssetFilePathByName(@NonNull String assetFileName) {
return flutterLoader.getLookupKeyForAsset(assetFileName);
}
public String getAssetFilePathByName(@NonNull String assetFileName, @NonNull String packageName) {
return flutterLoader.getLookupKeyForAsset(assetFileName, packageName);
}
public String getAssetFilePathBySubpath(@NonNull String assetSubpath) {
return flutterLoader.getLookupKeyForAsset(assetSubpath);
}
public String getAssetFilePathBySubpath(@NonNull String assetSubpath, @NonNull String packageName) {
return flutterLoader.getLookupKeyForAsset(assetSubpath, packageName);
}
}
private static class FlutterEngineActivityPluginBinding implements ActivityPluginBinding {
@NonNull
private final Activity activity;
......
......@@ -9,6 +9,7 @@ import android.content.Context;
import android.support.annotation.NonNull;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformViewRegistry;
import io.flutter.view.TextureRegistry;
......@@ -101,19 +102,22 @@ public interface FlutterPlugin {
private final BinaryMessenger binaryMessenger;
private final TextureRegistry textureRegistry;
private final PlatformViewRegistry platformViewRegistry;
private final FlutterAssets flutterAssets;
public FlutterPluginBinding(
@NonNull Context applicationContext,
@NonNull FlutterEngine flutterEngine,
@NonNull BinaryMessenger binaryMessenger,
@NonNull TextureRegistry textureRegistry,
@NonNull PlatformViewRegistry platformViewRegistry
@NonNull PlatformViewRegistry platformViewRegistry,
@NonNull FlutterAssets flutterAssets
) {
this.applicationContext = applicationContext;
this.flutterEngine = flutterEngine;
this.binaryMessenger = binaryMessenger;
this.textureRegistry = textureRegistry;
this.platformViewRegistry = platformViewRegistry;
this.flutterAssets = flutterAssets;
}
@NonNull
......@@ -146,5 +150,47 @@ public interface FlutterPlugin {
public PlatformViewRegistry getPlatformViewRegistry() {
return platformViewRegistry;
}
@NonNull
public FlutterAssets getFlutterAssets() {
return flutterAssets;
}
}
/**
* Provides Flutter plugins with access to Flutter asset information.
*/
interface FlutterAssets {
/**
* Returns the relative file path to the Flutter asset with the given name, including the file's
* extension, e.g., {@code "myImage.jpg"}.
*
* <p>The returned file path is relative to the Android app's standard assets directory.
* Therefore, the returned path is appropriate to pass to Android's {@code AssetManager},
* but the path is not appropriate to load as an absolute path.
*/
String getAssetFilePathByName(@NonNull String assetFileName);
/**
* Same as {@link #getAssetFilePathByName(String)} but with added support for an explicit
* Android {@code packageName}.
*/
String getAssetFilePathByName(@NonNull String assetFileName, @NonNull String packageName);
/**
* Returns the relative file path to the Flutter asset with the given subpath, including the file's
* extension, e.g., {@code "/dir1/dir2/myImage.jpg"}.
*
* <p>The returned file path is relative to the Android app's standard assets directory.
* Therefore, the returned path is appropriate to pass to Android's {@code AssetManager},
* but the path is not appropriate to load as an absolute path.
*/
String getAssetFilePathBySubpath(@NonNull String assetSubpath);
/**
* Same as {@link #getAssetFilePathBySubpath(String)} but with added support for an explicit
* Android {@code packageName}.
*/
String getAssetFilePathBySubpath(@NonNull String assetSubpath, @NonNull String packageName);
}
}
......@@ -23,6 +23,7 @@ import io.flutter.plugin.editing.TextInputPluginTest;
import io.flutter.plugin.platform.SingleViewPresentationTest;
import io.flutter.util.PreconditionsTest;
import test.io.flutter.embedding.engine.FlutterEngineTest;
import test.io.flutter.embedding.engine.PluginComponentTest;
import test.io.flutter.embedding.engine.dart.DartExecutorTest;
@RunWith(Suite.class)
......@@ -38,6 +39,7 @@ import test.io.flutter.embedding.engine.dart.DartExecutorTest;
FlutterRendererTest.class,
FlutterViewTest.class,
PlatformChannelTest.class,
PluginComponentTest.class,
PreconditionsTest.class,
RenderingComponentTest.class,
StandardMessageCodecTest.class,
......
package test.io.flutter.embedding.engine;
import android.support.annotation.NonNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@Config(manifest=Config.NONE)
@RunWith(RobolectricTestRunner.class)
public class PluginComponentTest {
@Test
public void pluginsCanAccessFlutterAssetPaths() {
// Setup test.
FlutterJNI flutterJNI = mock(FlutterJNI.class);
when(flutterJNI.isAttached()).thenReturn(true);
// FlutterLoader is the object to which the PluginRegistry defers for obtaining
// the path to a Flutter asset. Ideally in this component test we would use a
// real FlutterLoader and directly verify the relationship between FlutterAssets
// and FlutterLoader. However, a real FlutterLoader cannot be used in a JVM test
// because it would attempt to load native libraries. Therefore, we create a fake
// FlutterLoader, but then we defer the corresponding asset lookup methods to the
// real FlutterLoader singleton. This test ends up verifying that when FlutterAssets
// is queried for an asset path, it returns the real expected path based on real
// FlutterLoader behavior.
FlutterLoader flutterLoader = mock(FlutterLoader.class);
when(flutterLoader.getLookupKeyForAsset(any(String.class))).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
// Defer to a real FlutterLoader to return the asset path.
String fileNameOrSubpath = (String) invocation.getArguments()[0];
return FlutterLoader.getInstance().getLookupKeyForAsset(fileNameOrSubpath);
}
});
when(flutterLoader.getLookupKeyForAsset(any(String.class), any(String.class))).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
// Defer to a real FlutterLoader to return the asset path.
String fileNameOrSubpath = (String) invocation.getArguments()[0];
String packageName = (String) invocation.getArguments()[1];
return FlutterLoader.getInstance().getLookupKeyForAsset(fileNameOrSubpath, packageName);
}
});
// Execute behavior under test.
FlutterEngine flutterEngine = new FlutterEngine(
RuntimeEnvironment.application,
flutterLoader,
flutterJNI
);
// As soon as our plugin is registered it will look up asset paths and store them
// for our verification.
PluginThatAccessesAssets plugin = new PluginThatAccessesAssets();
flutterEngine.getPlugins().add(plugin);
// Verify results.
assertEquals("flutter_assets/fake_asset.jpg", plugin.getAssetPathBasedOnName());
assertEquals("flutter_assets/packages/fakepackage/fake_asset.jpg", plugin.getAssetPathBasedOnNameAndPackage());
assertEquals("flutter_assets/some/path/fake_asset.jpg", plugin.getAssetPathBasedOnSubpath());
assertEquals("flutter_assets/packages/fakepackage/some/path/fake_asset.jpg", plugin.getAssetPathBasedOnSubpathAndPackage());
}
private static class PluginThatAccessesAssets implements FlutterPlugin {
private String assetPathBasedOnName;
private String assetPathBasedOnNameAndPackage;
private String assetPathBasedOnSubpath;
private String assetPathBasedOnSubpathAndPackage;
public String getAssetPathBasedOnName() {
return assetPathBasedOnName;
}
public String getAssetPathBasedOnNameAndPackage() {
return assetPathBasedOnNameAndPackage;
}
public String getAssetPathBasedOnSubpath() {
return assetPathBasedOnSubpath;
}
public String getAssetPathBasedOnSubpathAndPackage() {
return assetPathBasedOnSubpathAndPackage;
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
assetPathBasedOnName = binding
.getFlutterAssets()
.getAssetFilePathByName("fake_asset.jpg");
assetPathBasedOnNameAndPackage = binding
.getFlutterAssets()
.getAssetFilePathByName("fake_asset.jpg", "fakepackage");
assetPathBasedOnSubpath = binding
.getFlutterAssets()
.getAssetFilePathByName("some/path/fake_asset.jpg");
assetPathBasedOnSubpathAndPackage = binding
.getFlutterAssets()
.getAssetFilePathByName("some/path/fake_asset.jpg", "fakepackage");
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册