Add template for plugin projects. (#9076)
Plugin projects are created by running `flutter create --plugin <name>`. An example app is also created in the plugin project, using the normal 'create' template, which has been modified to allow for conditional plugin code. Modified the android package name to match package naming conventions (all lower-case, and must match the directory name).
This commit is contained in:
parent
471c97df30
commit
f34f8a3197
@ -30,6 +30,12 @@ class CreateCommand extends FlutterCommand {
|
||||
defaultsTo: false,
|
||||
help: 'Also add a flutter_driver dependency and generate a sample \'flutter drive\' test.'
|
||||
);
|
||||
argParser.addFlag(
|
||||
'plugin',
|
||||
negatable: true,
|
||||
defaultsTo: false,
|
||||
help: 'Generate a new Flutter Plugin project.'
|
||||
);
|
||||
argParser.addOption(
|
||||
'description',
|
||||
defaultsTo: 'A new flutter project.',
|
||||
@ -80,9 +86,10 @@ class CreateCommand extends FlutterCommand {
|
||||
if (!fs.isFileSync(fs.path.join(flutterDriverPackagePath, 'pubspec.yaml')))
|
||||
throwToolExit('Unable to find package:flutter_driver in $flutterDriverPackagePath', exitCode: 2);
|
||||
|
||||
final bool generatePlugin = argResults['plugin'];
|
||||
|
||||
final Directory projectDir = fs.directory(argResults.rest.first);
|
||||
final String dirPath = fs.path.normalize(projectDir.absolute.path);
|
||||
final String relativePath = fs.path.relative(dirPath);
|
||||
final String projectName = _normalizeProjectName(fs.path.basename(dirPath));
|
||||
|
||||
String error =_validateProjectDir(dirPath, flutterRoot: flutterRoot);
|
||||
@ -93,24 +100,55 @@ class CreateCommand extends FlutterCommand {
|
||||
if (error != null)
|
||||
throwToolExit(error);
|
||||
|
||||
final int generatedCount = _renderTemplates(
|
||||
projectName,
|
||||
argResults['description'],
|
||||
dirPath,
|
||||
flutterPackagesDirectory,
|
||||
renderDriverTest: argResults['with-driver-test']
|
||||
final Map<String, dynamic> templateContext = _templateContext(
|
||||
projectName, argResults['description'], dirPath,
|
||||
flutterPackagesDirectory, renderDriverTest: argResults['with-driver-test'],
|
||||
withPluginHook: generatePlugin,
|
||||
);
|
||||
|
||||
printStatus('Creating project ${fs.path.relative(dirPath)}...');
|
||||
int generatedCount = 0;
|
||||
String appPath = dirPath;
|
||||
if (generatePlugin) {
|
||||
final String description = argResults.wasParsed('description')
|
||||
? argResults['description']
|
||||
: 'A new flutter plugin project.';
|
||||
templateContext['description'] = description;
|
||||
generatedCount += _renderTemplate('plugin', dirPath, templateContext);
|
||||
|
||||
if (argResults['pub'])
|
||||
await pubGet(directory: dirPath);
|
||||
|
||||
appPath = fs.path.join(dirPath, 'example');
|
||||
final String androidPluginIdentifier = templateContext['androidIdentifier'];
|
||||
final String exampleProjectName = projectName + '_example';
|
||||
templateContext['projectName'] = exampleProjectName;
|
||||
templateContext['androidIdentifier'] = _createAndroidIdentifier(exampleProjectName);
|
||||
templateContext['iosIdentifier'] = _createUTIIdentifier(exampleProjectName);
|
||||
templateContext['description'] = 'Demonstrates how to use the $projectName plugin.';
|
||||
templateContext['pluginProjectName'] = projectName;
|
||||
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
|
||||
}
|
||||
|
||||
generatedCount += _renderTemplate('create', appPath, templateContext);
|
||||
if (argResults['with-driver-test']) {
|
||||
final String testPath = fs.path.join(appPath, 'test_driver');
|
||||
generatedCount += _renderTemplate('driver', testPath, templateContext);
|
||||
}
|
||||
|
||||
printStatus('Wrote $generatedCount files.');
|
||||
printStatus('');
|
||||
|
||||
updateXcodeGeneratedProperties(dirPath, BuildMode.debug, flx.defaultMainPath);
|
||||
updateXcodeGeneratedProperties(appPath, BuildMode.debug, flx.defaultMainPath);
|
||||
|
||||
if (argResults['pub'])
|
||||
await pubGet(directory: dirPath);
|
||||
await pubGet(directory: appPath);
|
||||
|
||||
printStatus('');
|
||||
|
||||
// Run doctor; tell the user the next steps.
|
||||
final String relativeAppPath = fs.path.relative(appPath);
|
||||
final String relativePluginPath = fs.path.relative(dirPath);
|
||||
if (doctor.canLaunchAnything) {
|
||||
// Let them know a summary of the state of their tooling.
|
||||
await doctor.summary();
|
||||
@ -118,11 +156,18 @@ class CreateCommand extends FlutterCommand {
|
||||
printStatus('''
|
||||
All done! In order to run your application, type:
|
||||
|
||||
\$ cd $relativePath
|
||||
\$ cd $relativeAppPath
|
||||
\$ flutter run
|
||||
|
||||
Your main program file is lib/main.dart in the $relativePath directory.
|
||||
Your main program file is lib/main.dart in the $relativeAppPath directory.
|
||||
''');
|
||||
if (generatePlugin) {
|
||||
printStatus('''
|
||||
Your plugin code is in lib/$projectName.dart in the $relativePluginPath directory.
|
||||
|
||||
Host platform code is in the android/ and ios/ directories under $relativePluginPath.
|
||||
''');
|
||||
}
|
||||
} else {
|
||||
printStatus("You'll need to install additional components before you can run "
|
||||
"your Flutter app:");
|
||||
@ -133,48 +178,40 @@ Your main program file is lib/main.dart in the $relativePath directory.
|
||||
printStatus('');
|
||||
printStatus("After installing components, run 'flutter doctor' in order to "
|
||||
"re-validate your setup.");
|
||||
printStatus("When complete, type 'flutter run' from the '$relativePath' "
|
||||
printStatus("When complete, type 'flutter run' from the '$relativeAppPath' "
|
||||
"directory in order to launch your app.");
|
||||
printStatus("Your main program file is: $relativePath/lib/main.dart");
|
||||
printStatus("Your main program file is: $relativeAppPath/lib/main.dart");
|
||||
}
|
||||
}
|
||||
|
||||
int _renderTemplates(String projectName, String projectDescription, String dirPath,
|
||||
String flutterPackagesDirectory, { bool renderDriverTest: false }) {
|
||||
fs.directory(dirPath).createSync(recursive: true);
|
||||
|
||||
Map<String, dynamic> _templateContext(String projectName,
|
||||
String projectDescription, String dirPath, String flutterPackagesDirectory,
|
||||
{ bool renderDriverTest: false, bool withPluginHook: false }) {
|
||||
flutterPackagesDirectory = fs.path.normalize(flutterPackagesDirectory);
|
||||
flutterPackagesDirectory = _relativePath(from: dirPath, to: flutterPackagesDirectory);
|
||||
|
||||
printStatus('Creating project ${fs.path.relative(dirPath)}...');
|
||||
final String pluginDartClass = _createPluginClassName(projectName);
|
||||
final String pluginClass = pluginDartClass.endsWith('Plugin')
|
||||
? pluginDartClass
|
||||
: pluginDartClass + 'Plugin';
|
||||
|
||||
final Map<String, dynamic> templateContext = <String, dynamic>{
|
||||
return <String, dynamic>{
|
||||
'projectName': projectName,
|
||||
'androidIdentifier': _createAndroidIdentifier(projectName),
|
||||
'iosIdentifier': _createUTIIdentifier(projectName),
|
||||
'description': projectDescription,
|
||||
'flutterPackagesDirectory': flutterPackagesDirectory,
|
||||
'androidMinApiLevel': android.minApiLevel
|
||||
'androidMinApiLevel': android.minApiLevel,
|
||||
'withDriverTest': renderDriverTest,
|
||||
'pluginClass': pluginClass,
|
||||
'pluginDartClass': pluginDartClass,
|
||||
'withPluginHook': withPluginHook,
|
||||
};
|
||||
}
|
||||
|
||||
int fileCount = 0;
|
||||
|
||||
templateContext['withDriverTest'] = renderDriverTest;
|
||||
|
||||
final Template createTemplate = new Template.fromName('create');
|
||||
fileCount += createTemplate.render(
|
||||
fs.directory(dirPath),
|
||||
templateContext, overwriteExisting: false,
|
||||
projectName: projectName
|
||||
);
|
||||
|
||||
if (renderDriverTest) {
|
||||
final Template driverTemplate = new Template.fromName('driver');
|
||||
fileCount += driverTemplate.render(fs.directory(fs.path.join(dirPath, 'test_driver')),
|
||||
templateContext, overwriteExisting: false);
|
||||
}
|
||||
|
||||
return fileCount;
|
||||
int _renderTemplate(String templateName, String dirPath, Map<String, dynamic> context) {
|
||||
final Template template = new Template.fromName(templateName);
|
||||
return template.render(fs.directory(dirPath), context, overwriteExisting: false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +224,12 @@ String _normalizeProjectName(String name) {
|
||||
}
|
||||
|
||||
String _createAndroidIdentifier(String name) {
|
||||
return 'com.yourcompany.${camelCase(name)}';
|
||||
return 'com.yourcompany.$name';
|
||||
}
|
||||
|
||||
String _createPluginClassName(String name) {
|
||||
final String camelizedName = camelCase(name);
|
||||
return camelizedName[0].toUpperCase() + camelizedName.substring(1);
|
||||
}
|
||||
|
||||
String _createUTIIdentifier(String name) {
|
||||
|
@ -62,11 +62,12 @@ class Template {
|
||||
Directory destination,
|
||||
Map<String, dynamic> context, {
|
||||
bool overwriteExisting: true,
|
||||
String projectName
|
||||
}) {
|
||||
destination.createSync(recursive: true);
|
||||
int fileCount = 0;
|
||||
|
||||
final String projectName = context['projectName'];
|
||||
final String pluginClass = context['pluginClass'];
|
||||
final String destinationDirPath = destination.absolute.path;
|
||||
|
||||
_templateFilePaths.forEach((String relativeDestPath, String absoluteSrcPath) {
|
||||
@ -76,6 +77,8 @@ class Template {
|
||||
.replaceAll(_kTemplateExtension, '');
|
||||
if (projectName != null)
|
||||
finalDestinationPath = finalDestinationPath.replaceAll('projectName', projectName);
|
||||
if (pluginClass != null)
|
||||
finalDestinationPath = finalDestinationPath.replaceAll('pluginClass', pluginClass);
|
||||
final File finalDestinationFile = fs.file(finalDestinationPath);
|
||||
final String relativePathForLogging = fs.path.relative(finalDestinationFile.path);
|
||||
|
||||
|
@ -2,11 +2,16 @@ package {{androidIdentifier}};
|
||||
|
||||
import android.os.Bundle;
|
||||
import io.flutter.app.FlutterActivity;
|
||||
{{#withPluginHook}}
|
||||
import {{androidPluginIdentifier}}.{{pluginClass}};
|
||||
{{/withPluginHook}}
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
{{#withPluginHook}}
|
||||
{{pluginClass}}.register(this);
|
||||
{{/withPluginHook}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,22 @@
|
||||
#include "AppDelegate.h"
|
||||
{{#withPluginHook}}
|
||||
#include "{{pluginClass}}.h"
|
||||
|
||||
@implementation AppDelegate {
|
||||
{{pluginClass}} *_{{pluginProjectName}};
|
||||
}
|
||||
{{/withPluginHook}}
|
||||
{{^withPluginHook}}
|
||||
@implementation AppDelegate
|
||||
{{/withPluginHook}}
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
// Override point for customization after application launch.
|
||||
{{#withPluginHook}}
|
||||
FlutterViewController *flutterController =
|
||||
(FlutterViewController *)self.window.rootViewController;
|
||||
_{{pluginProjectName}} = [[{{pluginClass}} alloc] initWithFlutterView:flutterController];
|
||||
{{/withPluginHook}}
|
||||
return YES;
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
|
||||
{{#withDriverTest}}
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
{{/withDriverTest}}
|
||||
{{#withPluginHook}}
|
||||
import 'package:{{pluginProjectName}}/{{pluginProjectName}}.dart';
|
||||
{{/withPluginHook}}
|
||||
|
||||
void main() {
|
||||
{{#withDriverTest}}
|
||||
@ -55,6 +58,19 @@ class MyHomePage extends StatefulWidget {
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
{{#withPluginHook}}
|
||||
String _platformVersion = 'Unknown';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
{{pluginDartClass}}.platformVersion.then((String platformVersion) {
|
||||
setState(() {
|
||||
_platformVersion = platformVersion;
|
||||
});
|
||||
});
|
||||
}
|
||||
{{/withPluginHook}}
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
@ -84,9 +100,21 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
title: new Text(config.title),
|
||||
),
|
||||
body: new Center(
|
||||
{{#withPluginHook}}
|
||||
child: new Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
new Text('Running on: $_platformVersion\n'),
|
||||
new Text(
|
||||
'Button tapped $_counter time${ _counter == 1 ? '' : 's' }.'),
|
||||
],
|
||||
),
|
||||
{{/withPluginHook}}
|
||||
{{^withPluginHook}}
|
||||
child: new Text(
|
||||
'Button tapped $_counter time${ _counter == 1 ? '' : 's' }.',
|
||||
),
|
||||
{{/withPluginHook}}
|
||||
),
|
||||
floatingActionButton: new FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
|
@ -9,6 +9,10 @@ dev_dependencies:
|
||||
flutter_driver:
|
||||
sdk: flutter
|
||||
{{/withDriverTest}}
|
||||
{{#withPluginHook}}
|
||||
{{pluginProjectName}}:
|
||||
path: ../
|
||||
{{/withPluginHook}}
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||
|
9
packages/flutter_tools/templates/plugin/.gitignore.tmpl
Normal file
9
packages/flutter_tools/templates/plugin/.gitignore.tmpl
Normal file
@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
.atom/
|
||||
.idea
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
ios/.generated/
|
||||
packages
|
||||
pubspec.lock
|
27
packages/flutter_tools/templates/plugin/LICENSE.tmpl
Normal file
27
packages/flutter_tools/templates/plugin/LICENSE.tmpl
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 Your Company. 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 Your Company 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.
|
8
packages/flutter_tools/templates/plugin/README.md.tmpl
Normal file
8
packages/flutter_tools/templates/plugin/README.md.tmpl
Normal file
@ -0,0 +1,8 @@
|
||||
# {{projectName}}
|
||||
|
||||
{{description}}
|
||||
|
||||
## Getting Started
|
||||
|
||||
For help getting started with Flutter, view our online
|
||||
[documentation](http://flutter.io/).
|
12
packages/flutter_tools/templates/plugin/android.tmpl/.gitignore
vendored
Normal file
12
packages/flutter_tools/templates/plugin/android.tmpl/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
||||
/gradle
|
||||
/gradlew
|
||||
/gradlew.bat
|
@ -0,0 +1,32 @@
|
||||
group '{{androidIdentifier}}'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.0'
|
||||
|
||||
defaultConfig {
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
lintOptions {
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
@ -0,0 +1 @@
|
||||
rootProject.name = '{{projectName}}'
|
@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="{{androidIdentifier}}"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.0.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
|
||||
</manifest>
|
@ -0,0 +1,35 @@
|
||||
package {{androidIdentifier}};
|
||||
|
||||
import io.flutter.app.FlutterActivity;
|
||||
import io.flutter.plugin.common.FlutterMethodChannel;
|
||||
import io.flutter.plugin.common.FlutterMethodChannel.MethodCallHandler;
|
||||
import io.flutter.plugin.common.FlutterMethodChannel.Response;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {{pluginClass}}
|
||||
*/
|
||||
public class {{pluginClass}} implements MethodCallHandler {
|
||||
private FlutterActivity activity;
|
||||
|
||||
public static void register(FlutterActivity activity) {
|
||||
new {{pluginClass}}(activity);
|
||||
}
|
||||
|
||||
private {{pluginClass}}(FlutterActivity activity) {
|
||||
this.activity = activity;
|
||||
new FlutterMethodChannel(activity.getFlutterView(), "{{projectName}}").setMethodCallHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, Response response) {
|
||||
if (call.method.equals("getPlatformVersion")) {
|
||||
response.success("Android " + android.os.Build.VERSION.RELEASE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown method " + call.method);
|
||||
}
|
||||
}
|
||||
}
|
31
packages/flutter_tools/templates/plugin/ios.tmpl/.gitignore
vendored
Normal file
31
packages/flutter_tools/templates/plugin/ios.tmpl/.gitignore
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
.idea/
|
||||
.vagrant/
|
||||
.sconsign.dblite
|
||||
.svn/
|
||||
|
||||
.DS_Store
|
||||
*.swp
|
||||
profile
|
||||
|
||||
DerivedData/
|
||||
build/
|
||||
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
|
||||
xcuserdata
|
||||
|
||||
*.moved-aside
|
||||
|
||||
*.pyc
|
||||
*sync/
|
||||
Icon?
|
||||
.tags*
|
||||
|
@ -0,0 +1,5 @@
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@interface {{pluginClass}} : NSObject
|
||||
- initWithFlutterView:(FlutterViewController *)flutterView;
|
||||
@end
|
@ -0,0 +1,25 @@
|
||||
#import "{{pluginClass}}.h"
|
||||
|
||||
@implementation {{pluginClass}} {
|
||||
}
|
||||
|
||||
- (instancetype)initWithFlutterView:(FlutterViewController *)flutterView {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
FlutterMethodChannel *channel = [FlutterMethodChannel
|
||||
methodChannelNamed:@"{{projectName}}"
|
||||
binaryMessenger:flutterView
|
||||
codec:[FlutterStandardMethodCodec sharedInstance]];
|
||||
[channel setMethodCallHandler:^(FlutterMethodCall *call,
|
||||
FlutterResultReceiver result) {
|
||||
if ([@"getPlatformVersion" isEqualToString:call.method]) {
|
||||
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice]
|
||||
systemVersion]],
|
||||
nil);
|
||||
}
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,19 @@
|
||||
#
|
||||
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
|
||||
#
|
||||
Pod::Spec.new do |s|
|
||||
s.name = '{{projectName}}'
|
||||
s.version = '0.0.1'
|
||||
s.summary = '{{description}}'
|
||||
s.description = <<-DESC
|
||||
{{description}}
|
||||
DESC
|
||||
s.homepage = 'http://example.com'
|
||||
s.license = { :file => '../LICENSE' }
|
||||
s.author = { 'Your Company' => 'email@example.com' }
|
||||
s.source = { :path => '.' }
|
||||
s.source_files = 'Classes/**/*'
|
||||
s.public_header_files = 'Classes/**/*.h'
|
||||
s.dependency 'Flutter'
|
||||
end
|
||||
|
@ -0,0 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class {{pluginDartClass}} {
|
||||
static const PlatformMethodChannel _channel =
|
||||
const PlatformMethodChannel('{{projectName}}');
|
||||
|
||||
static Future<String> get platformVersion =>
|
||||
_channel.invokeMethod('getPlatformVersion');
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
name: {{projectName}}
|
||||
description: {{description}}
|
||||
|
||||
flutter:
|
||||
plugin:
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
Loading…
x
Reference in New Issue
Block a user