Unverified Commit 90d978f8 authored by Chris Bracken's avatar Chris Bracken Committed by GitHub

Add windowsIdentifier template parameter (#82588)

Windows package identifiers are globally unique strings, typically a
GUID. These are required for templates that require a Windows package
name as described in
https://docs.microsoft.com/en-us/windows/win32/appxpkg/appx-portal

Fixes https://github.com/flutter/flutter/issues/82587
parent 71a7909f
......@@ -423,9 +423,10 @@ Your $application code is in $relativeAppMain.
final String androidPluginIdentifier = templateContext['androidIdentifier'] as String;
final String exampleProjectName = projectName + '_example';
templateContext['projectName'] = exampleProjectName;
templateContext['androidIdentifier'] = createAndroidIdentifier(organization, exampleProjectName);
templateContext['iosIdentifier'] = createUTIIdentifier(organization, exampleProjectName);
templateContext['macosIdentifier'] = createUTIIdentifier(organization, exampleProjectName);
templateContext['androidIdentifier'] = CreateBase.createAndroidIdentifier(organization, exampleProjectName);
templateContext['iosIdentifier'] = CreateBase.createUTIIdentifier(organization, exampleProjectName);
templateContext['macosIdentifier'] = CreateBase.createUTIIdentifier(organization, exampleProjectName);
templateContext['windowsIdentifier'] = CreateBase.createWindowsIdentifier(organization, exampleProjectName);
templateContext['description'] = 'Demonstrates how to use the $projectName plugin.';
templateContext['pluginProjectName'] = projectName;
templateContext['androidPluginIdentifier'] = androidPluginIdentifier;
......
......@@ -340,6 +340,8 @@ abstract class CreateBase extends FlutterCommand {
createUTIIdentifier(organization, projectName);
final String androidIdentifier =
createAndroidIdentifier(organization, projectName);
final String windowsIdentifier =
createWindowsIdentifier(organization, projectName);
// Linux uses the same scheme as the Android identifier.
// https://developer.gnome.org/gio/stable/GApplication.html#g-application-id-is-valid
final String linuxIdentifier = androidIdentifier;
......@@ -351,6 +353,7 @@ abstract class CreateBase extends FlutterCommand {
'iosIdentifier': appleIdentifier,
'macosIdentifier': appleIdentifier,
'linuxIdentifier': linuxIdentifier,
'windowsIdentifier': windowsIdentifier,
'description': projectDescription,
'dartSdk': '$flutterRoot/bin/cache/dart-sdk',
'androidMinApiLevel': android_common.minApiLevel,
......@@ -444,8 +447,7 @@ abstract class CreateBase extends FlutterCommand {
///
/// Android application ID is specified in: https://developer.android.com/studio/build/application-id
/// All characters must be alphanumeric or an underscore [a-zA-Z0-9_].
@protected
String createAndroidIdentifier(String organization, String name) {
static String createAndroidIdentifier(String organization, String name) {
String tmpIdentifier = '$organization.$name';
final RegExp disallowed = RegExp(r'[^\w\.]');
tmpIdentifier = tmpIdentifier.replaceAll(disallowed, '');
......@@ -470,14 +472,20 @@ abstract class CreateBase extends FlutterCommand {
return prefixedSegments.join('.');
}
/// Creates a Windows package name.
///
/// Package names must be a globally unique, commonly a GUID.
static String createWindowsIdentifier(String organization, String name) {
return const Uuid().v4().toUpperCase();
}
String _createPluginClassName(String name) {
final String camelizedName = camelCase(name);
return camelizedName[0].toUpperCase() + camelizedName.substring(1);
}
/// Create a UTI (https://en.wikipedia.org/wiki/Uniform_Type_Identifier) from a base name
@protected
String createUTIIdentifier(String organization, String name) {
static String createUTIIdentifier(String organization, String name) {
name = camelCase(name);
String tmpIdentifier = '$organization.$name';
final RegExp disallowed = RegExp(r'[^a-zA-Z0-9\-\.\u0080-\uffff]+');
......
......@@ -18,6 +18,7 @@ import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/create.dart';
import 'package:flutter_tools/src/commands/create_base.dart';
import 'package:flutter_tools/src/dart/pub.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
......@@ -26,6 +27,7 @@ import 'package:flutter_tools/src/version.dart';
import 'package:process/process.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:uuid/uuid.dart';
import '../../src/common.dart';
import '../../src/context.dart';
......@@ -83,6 +85,28 @@ void main() {
await _restoreFlutterToolsSnapshot();
});
test('createAndroidIdentifier emits a valid identifier', () {
final String identifier = CreateBase.createAndroidIdentifier('42org', '8project');
expect(identifier.contains('.'), isTrue);
final RegExp startsWithLetter = RegExp(r'^[a-zA-Z][\w]*$');
final List<String> segments = identifier.split('.');
for (final String segment in segments) {
expect(startsWithLetter.hasMatch(segment), isTrue);
}
});
test('createUTIIdentifier emits a valid identifier', () {
final String identifier = CreateBase.createUTIIdentifier('org@', 'project');
expect(identifier.contains('.'), isTrue);
expect(identifier.contains('@'), isFalse);
});
test('createWindowsIdentifier emits a GUID', () {
final String identifier = CreateBase.createWindowsIdentifier('org', 'project');
expect(Uuid.isValidUUID(fromString: identifier), isTrue);
});
// Verify that we create a default project ('app') that is
// well-formed.
testUsingContext('can create a default project', () async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment