Inject plugin registration. (#9216)
Added a PluginRegistry to the new project template. The registry files will be automatically updated at build time to register the native plugins. Fixes #7814.
This commit is contained in:
parent
4f258357c9
commit
7ffa82aaf0
@ -156,7 +156,7 @@ Future<Null> buildGradleProject(BuildMode buildMode, String target, String kerne
|
||||
settings.values['flutter.buildMode'] = buildModeName;
|
||||
settings.writeContents(localProperties);
|
||||
|
||||
writeFlutterPluginsList();
|
||||
injectPlugins();
|
||||
|
||||
final String gradle = ensureGradle();
|
||||
|
||||
|
@ -15,6 +15,7 @@ import '../doctor.dart';
|
||||
import '../flx.dart' as flx;
|
||||
import '../globals.dart';
|
||||
import '../ios/xcodeproj.dart';
|
||||
import '../plugins.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import '../template.dart';
|
||||
|
||||
@ -141,8 +142,10 @@ class CreateCommand extends FlutterCommand {
|
||||
|
||||
updateXcodeGeneratedProperties(appPath, BuildMode.debug, flx.defaultMainPath);
|
||||
|
||||
if (argResults['pub'])
|
||||
if (argResults['pub']) {
|
||||
await pubGet(directory: appPath);
|
||||
injectPlugins(directory: appPath);
|
||||
}
|
||||
|
||||
printStatus('');
|
||||
|
||||
|
@ -152,7 +152,7 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
// copied over to a location that is suitable for Xcodebuild to find them.
|
||||
final Directory appDirectory = fs.directory(app.appDirectory);
|
||||
await _addServicesToBundle(appDirectory);
|
||||
writeFlutterPluginsList();
|
||||
injectPlugins();
|
||||
|
||||
await _runPodInstall(appDirectory, flutterFrameworkDir(mode));
|
||||
|
||||
|
@ -2,46 +2,69 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:mustache/mustache.dart' as mustache;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'base/file_system.dart';
|
||||
import 'dart/package_map.dart';
|
||||
import 'globals.dart';
|
||||
|
||||
dynamic _loadYamlFile(String path) {
|
||||
if (!fs.isFileSync(path))
|
||||
return null;
|
||||
final String manifestString = fs.file(path).readAsStringSync();
|
||||
return loadYaml(manifestString);
|
||||
class Plugin {
|
||||
final String name;
|
||||
final String path;
|
||||
final String pluginClass;
|
||||
final String androidPackage;
|
||||
|
||||
Plugin(this.name, this.path, this.pluginClass, this.androidPackage);
|
||||
|
||||
factory Plugin.fromYaml(String name, String path, dynamic pluginYaml) {
|
||||
String androidPackage;
|
||||
String pluginClass;
|
||||
if (pluginYaml != null) {
|
||||
androidPackage = pluginYaml['androidPackage'];
|
||||
pluginClass = pluginYaml['pluginClass'];
|
||||
}
|
||||
return new Plugin(name, path, pluginClass, androidPackage);
|
||||
}
|
||||
}
|
||||
|
||||
String _generatePluginManifest() {
|
||||
Plugin _pluginFromPubspec(String name, Uri packageRoot) {
|
||||
final String pubspecPath = packageRoot.resolve('pubspec.yaml').path;
|
||||
if (!fs.isFileSync(pubspecPath))
|
||||
return null;
|
||||
final dynamic pubspec = loadYaml(fs.file(pubspecPath).readAsStringSync());
|
||||
if (pubspec == null)
|
||||
return null;
|
||||
final dynamic flutterConfig = pubspec['flutter'];
|
||||
if (flutterConfig == null || !flutterConfig.containsKey('plugin'))
|
||||
return null;
|
||||
printTrace('Found plugin $name at ${packageRoot.path}');
|
||||
return new Plugin.fromYaml(name, packageRoot.path, flutterConfig['plugin']);
|
||||
}
|
||||
|
||||
List<Plugin> _findPlugins(String directory) {
|
||||
final List<Plugin> plugins = <Plugin>[];
|
||||
Map<String, Uri> packages;
|
||||
try {
|
||||
packages = new PackageMap(PackageMap.globalPackagesPath).map;
|
||||
final String packagesFile = fs.path.join(directory, PackageMap.globalPackagesPath);
|
||||
packages = new PackageMap(packagesFile).map;
|
||||
} on FormatException catch(e) {
|
||||
printTrace('Invalid .packages file: $e');
|
||||
return '';
|
||||
return plugins;
|
||||
}
|
||||
final List<String> plugins = <String>[];
|
||||
packages.forEach((String name, Uri uri) {
|
||||
final Uri packageRoot = uri.resolve('..');
|
||||
final dynamic packageConfig = _loadYamlFile(packageRoot.resolve('pubspec.yaml').path);
|
||||
if (packageConfig != null) {
|
||||
final dynamic flutterConfig = packageConfig['flutter'];
|
||||
if (flutterConfig != null && flutterConfig.containsKey('plugin')) {
|
||||
printTrace('Found plugin $name at ${packageRoot.path}');
|
||||
plugins.add('$name=${packageRoot.path}');
|
||||
}
|
||||
}
|
||||
final Plugin plugin = _pluginFromPubspec(name, packageRoot);
|
||||
if (plugin != null)
|
||||
plugins.add(plugin);
|
||||
});
|
||||
return plugins.join('\n');
|
||||
return plugins;
|
||||
}
|
||||
|
||||
void writeFlutterPluginsList() {
|
||||
final File pluginsProperties = fs.file('.flutter-plugins');
|
||||
|
||||
final String pluginManifest = _generatePluginManifest();
|
||||
void _writeFlutterPluginsList(String directory, List<Plugin> plugins) {
|
||||
final File pluginsProperties = fs.file(fs.path.join(directory, '.flutter-plugins'));
|
||||
final String pluginManifest =
|
||||
plugins.map((Plugin p) => '${p.name}=${p.path}').join('\n');
|
||||
if (pluginManifest.isNotEmpty) {
|
||||
pluginsProperties.writeAsStringSync('$pluginManifest\n');
|
||||
} else {
|
||||
@ -50,3 +73,132 @@ void writeFlutterPluginsList() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const String _androidPluginRegistryTemplate = '''package io.flutter.plugins;
|
||||
|
||||
import io.flutter.app.FlutterActivity;
|
||||
|
||||
{{#plugins}}
|
||||
import {{package}}.{{class}};
|
||||
{{/plugins}}
|
||||
|
||||
/**
|
||||
* Generated file. Do not edit.
|
||||
*/
|
||||
|
||||
public class PluginRegistry {
|
||||
{{#plugins}}
|
||||
public {{class}} {{name}};
|
||||
{{/plugins}}
|
||||
|
||||
public void registerAll(FlutterActivity activity) {
|
||||
{{#plugins}}
|
||||
{{name}} = {{class}}.register(activity);
|
||||
{{/plugins}}
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
void _writeAndroidPluginRegistry(String directory, List<Plugin> plugins) {
|
||||
final List<Map<String, dynamic>> androidPlugins = plugins
|
||||
.where((Plugin p) => p.androidPackage != null && p.pluginClass != null)
|
||||
.map((Plugin p) => <String, dynamic>{
|
||||
'name': p.name,
|
||||
'package': p.androidPackage,
|
||||
'class': p.pluginClass,
|
||||
})
|
||||
.toList();
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': androidPlugins,
|
||||
};
|
||||
|
||||
final String pluginRegistry =
|
||||
new mustache.Template(_androidPluginRegistryTemplate).renderString(context);
|
||||
final String javaSourcePath = fs.path.join(directory, 'android', 'app', 'src', 'main', 'java');
|
||||
final Directory registryDirectory =
|
||||
fs.directory(fs.path.join(javaSourcePath, 'io', 'flutter', 'plugins'));
|
||||
registryDirectory.createSync(recursive: true);
|
||||
final File registryFile = registryDirectory.childFile('PluginRegistry.java');
|
||||
registryFile.writeAsStringSync(pluginRegistry);
|
||||
}
|
||||
|
||||
const String _iosPluginRegistryHeaderTemplate = '''//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
#ifndef PluginRegistry_h
|
||||
#define PluginRegistry_h
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
{{#plugins}}
|
||||
#import "{{class}}.h"
|
||||
{{/plugins}}
|
||||
|
||||
@interface PluginRegistry : NSObject
|
||||
|
||||
{{#plugins}}
|
||||
@property (readonly, nonatomic) {{class}} *{{name}};
|
||||
{{/plugins}}
|
||||
|
||||
- (instancetype)initWithController:(FlutterViewController *)controller;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* PluginRegistry_h */
|
||||
''';
|
||||
|
||||
const String _iosPluginRegistryImplementationTemplate = '''//
|
||||
// Generated file. Do not edit.
|
||||
//
|
||||
|
||||
#import "PluginRegistry.h"
|
||||
|
||||
@implementation PluginRegistry
|
||||
|
||||
- (instancetype)initWithController:(FlutterViewController *)controller {
|
||||
if (self = [super init]) {
|
||||
{{#plugins}}
|
||||
_{{name}} = [[{{class}} alloc] initWithController:controller];
|
||||
{{/plugins}}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
''';
|
||||
|
||||
void _writeIOSPluginRegistry(String directory, List<Plugin> plugins) {
|
||||
final List<Map<String, dynamic>> iosPlugins = plugins
|
||||
.where((Plugin p) => p.pluginClass != null)
|
||||
.map((Plugin p) => <String, dynamic>{
|
||||
'name': p.name,
|
||||
'class': p.pluginClass,
|
||||
}).
|
||||
toList();
|
||||
final Map<String, dynamic> context = <String, dynamic>{
|
||||
'plugins': iosPlugins,
|
||||
};
|
||||
|
||||
final String pluginRegistryHeader =
|
||||
new mustache.Template(_iosPluginRegistryHeaderTemplate).renderString(context);
|
||||
final String pluginRegistryImplementation =
|
||||
new mustache.Template(_iosPluginRegistryImplementationTemplate).renderString(context);
|
||||
final Directory registryDirectory = fs.directory(fs.path.join(directory, 'ios', 'Runner'));
|
||||
registryDirectory.createSync(recursive: true);
|
||||
final File registryHeaderFile = registryDirectory.childFile('PluginRegistry.h');
|
||||
registryHeaderFile.writeAsStringSync(pluginRegistryHeader);
|
||||
final File registryImplementationFile = registryDirectory.childFile('PluginRegistry.m');
|
||||
registryImplementationFile.writeAsStringSync(pluginRegistryImplementation);
|
||||
|
||||
}
|
||||
|
||||
void injectPlugins({String directory}) {
|
||||
directory ??= fs.currentDirectory.path;
|
||||
final List<Plugin> plugins = _findPlugins(directory);
|
||||
_writeFlutterPluginsList(directory, plugins);
|
||||
if (fs.isDirectorySync(fs.path.join(directory, 'android')))
|
||||
_writeAndroidPluginRegistry(directory, plugins);
|
||||
if (fs.isDirectorySync(fs.path.join(directory, 'ios')))
|
||||
_writeIOSPluginRegistry(directory, plugins);
|
||||
}
|
||||
|
@ -2,16 +2,15 @@ package {{androidIdentifier}};
|
||||
|
||||
import android.os.Bundle;
|
||||
import io.flutter.app.FlutterActivity;
|
||||
{{#withPluginHook}}
|
||||
import {{androidPluginIdentifier}}.{{pluginClass}};
|
||||
{{/withPluginHook}}
|
||||
import io.flutter.plugins.PluginRegistry;
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
PluginRegistry pluginRegistry;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
{{#withPluginHook}}
|
||||
{{pluginClass}}.register(this);
|
||||
{{/withPluginHook}}
|
||||
pluginRegistry = new PluginRegistry();
|
||||
pluginRegistry.registerAll(this);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* PluginRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* PluginRegistry.m */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
|
||||
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -39,6 +40,8 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* PluginRegistry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PluginRegistry.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* PluginRegistry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PluginRegistry.m; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
|
||||
4D558BB7489B1C82B42A9097 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@ -121,6 +124,8 @@
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
97C146F11CF9000F007C117D /* Supporting Files */,
|
||||
1498D2321E8E86230040F4C2 /* PluginRegistry.h */,
|
||||
1498D2331E8E89220040F4C2 /* PluginRegistry.m */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
@ -299,6 +304,7 @@
|
||||
files = (
|
||||
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
|
||||
97C146F31CF9000F007C117D /* main.m in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* PluginRegistry.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1,23 +1,16 @@
|
||||
#include "AppDelegate.h"
|
||||
{{#withPluginHook}}
|
||||
#include "{{pluginClass}}.h"
|
||||
#include "PluginRegistry.h"
|
||||
|
||||
@implementation AppDelegate {
|
||||
{{pluginClass}} *_{{pluginProjectName}};
|
||||
PluginRegistry *plugins;
|
||||
}
|
||||
{{/withPluginHook}}
|
||||
{{^withPluginHook}}
|
||||
@implementation AppDelegate
|
||||
{{/withPluginHook}}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
// Override point for customization after application launch.
|
||||
{{#withPluginHook}}
|
||||
// Override point for customization after application launch.
|
||||
FlutterViewController *flutterController =
|
||||
(FlutterViewController *)self.window.rootViewController;
|
||||
_{{pluginProjectName}} = [[{{pluginClass}} alloc] initWithController:flutterController];
|
||||
{{/withPluginHook}}
|
||||
return YES;
|
||||
plugins = [[PluginRegistry alloc] initWithController:flutterController];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
@ -12,8 +12,8 @@ import io.flutter.plugin.common.MethodCall;
|
||||
public class {{pluginClass}} implements MethodCallHandler {
|
||||
private FlutterActivity activity;
|
||||
|
||||
public static void register(FlutterActivity activity) {
|
||||
new {{pluginClass}}(activity);
|
||||
public static {{pluginClass}} register(FlutterActivity activity) {
|
||||
return new {{pluginClass}}(activity);
|
||||
}
|
||||
|
||||
private {{pluginClass}}(FlutterActivity activity) {
|
||||
|
@ -3,6 +3,8 @@ description: {{description}}
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
androidPackage: {{androidIdentifier}}
|
||||
pluginClass: {{pluginClass}}
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
Loading…
x
Reference in New Issue
Block a user