Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update application identifier #148

Merged
merged 11 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/.cspell/words_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CLIs # Plural of the abbreviation for Command Line Interface.
CLI's # Belonging to a CLI.
CHANGELOGS # Plural of CHANGELOG
dependabot # Automated dependency updates built into GitHub.
deserializes # The process of reconstructing a data structure or object from a series of bytes or a string in order to instantiate the object for consumption.
docusaurs # An optimized site generator in React.
genhtml # Tool to generate an HTML view from LCOV coverage data files.
gradlew # Wrapper tool that uses Gradle.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ if (keystorePropertiesFile.exists()) {
}

android {
namespace "{{application_id_android}}"
namespace "{{android_namespace}}"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion

Expand All @@ -48,7 +48,7 @@ android {

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "{{application_id_android}}"
applicationId "{{android_application_id}}"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{org_name.dotCase()}}.{{project_name.snakeCase()}}">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{org_name.dotCase()}}.{{project_name.snakeCase()}}">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="${appName}"
android:name="${applicationName}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package {{org_name.dotCase()}}.{{project_name.snakeCase()}}
package {{android_namespace}}

import io.flutter.embedding.android.FlutterActivity

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{org_name.dotCase()}}.{{project_name.snakeCase()}}">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}};
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}};
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand All @@ -390,7 +390,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down Expand Up @@ -466,7 +466,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}};
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}};
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -482,7 +482,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down Expand Up @@ -554,7 +554,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}};
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}};
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -570,7 +570,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}};
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}};
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down Expand Up @@ -647,7 +647,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.dev;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand All @@ -664,7 +664,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down Expand Up @@ -738,7 +738,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.dev;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -754,7 +754,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down Expand Up @@ -828,7 +828,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.dev;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.dev;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -844,7 +844,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down Expand Up @@ -921,7 +921,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.stg;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.stg;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand All @@ -938,7 +938,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand Down Expand Up @@ -1014,7 +1014,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.stg;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.stg;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -1030,7 +1030,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down Expand Up @@ -1102,7 +1102,7 @@
"@executable_path/Frameworks",
);
PACKAGE_CONFIG = .dart_tool/package_config.json;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.stg;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.stg;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -1118,7 +1118,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = {{application_id}}.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = {{ios_application_id}}.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ BEGIN
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "{{application_id}}" "\0"
VALUE "CompanyName", "{{windows_application_id}}" "\0"
VALUE "FileDescription", "{{project_name.snakeCase()}}" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "{{project_name.snakeCase()}}" "\0"
VALUE "LegalCopyright", "Copyright (C) 2022 {{application_id}}. All rights reserved." "\0"
VALUE "LegalCopyright", "Copyright (C) 2022 {{windows_application_id}}. All rights reserved." "\0"
VALUE "OriginalFilename", "{{project_name.snakeCase()}}.exe" "\0"
VALUE "ProductName", "{{project_name.titleCase()}}" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
Expand Down
71 changes: 71 additions & 0 deletions very_good_core/hooks/lib/src/models/android_application_id.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import 'package:mason/mason.dart';

/// {@template android_application_id}
/// Every Android app has a unique application ID that looks like a Java or
/// Kotlin package name, such as `com.example.app`.
///
/// This ID uniquely identifies your app on the device and in the Google Play
/// Store.
///
/// See also:
///
/// * [Set the application ID Android documentation](https://developer.android.com/build/configure-app-module#set-application-id)
/// {@endtemplate}
extension type AndroidApplicationId(String value) {
/// Creates a new [AndroidApplicationId] from the provided [organizationName]
/// and [projectName].
///
/// This is the default fallback value for the application ID.
factory AndroidApplicationId.fallback({
required String organizationName,
required String projectName,
}) {
final segments = <String>[];
for (final segment in organizationName.split('.')) {
if (segment.isEmpty) continue;
segments.add(segment.snakeCase);
}
segments.add(projectName.snakeCase);

return AndroidApplicationId(segments.join('.'));
}

/// Checks if the [AndroidApplicationId] is valid, returning `true` if it is
/// and `false` otherwise.
///
/// Although the application ID looks like a traditional Kotlin or Java
/// package name, the naming rules for the application ID are a bit more
/// restrictive:
///
/// * It must have at least two segments (one or more dots).
/// * Each segment must start with a letter.
/// * All characters must be alphanumeric or an underscore [a-zA-Z0-9_].
///
/// See also:
///
/// * [Set the application ID Android documentation](https://developer.android.com/build/configure-app-module#set-application-id)
bool get isValid {
final segments = value.split('.');
if (segments.length < 2) {
// It must have at least two segments (one or more dots).
return false;
}

final isLetter = RegExp('^[a-zA-Z]');
final isAlphanumeric = RegExp(r'^[a-zA-Z0-9_]+$');

for (final segment in segments) {
if (segment.isEmpty || !isLetter.hasMatch(segment[0])) {
// Each segment must start with a letter.
return false;
}

if (!isAlphanumeric.hasMatch(segment)) {
// All characters must be alphanumeric or an underscore [a-zA-Z0-9_].
return false;
}
}

return true;
}
}
40 changes: 40 additions & 0 deletions very_good_core/hooks/lib/src/models/android_namespace.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:very_good_core_hooks/very_good_core_hooks.dart';

/// {@template android_namespace}
/// Every Android module has a namespace, which is used as the Kotlin or Java
/// package name for its generated R and BuildConfig classes.
///
/// The namespace can be different than the application ID, but it is usually
/// kept the same for a simpler workflow.
///
/// The name you set for the build.gradle file's namespace property should
/// always match your project's base package name, where you keep your
/// activities and other app code. You can have other sub-packages in your
/// project, but those files must import the R class using the namespace from
/// the namespace property.
///
/// See also:
///
/// * [Set the namespace Android documentation](https://developer.android.com/studio/build/application-id)
/// {@endtemplate}
extension type AndroidNamespace(String value) {
/// Creates a new [AndroidNamespace] from the provided [applicationId].
///
/// If a specific namespace is not provided, the namespace will default to the
/// application ID.
///
/// It is recommended to keep the namespace the same as the application ID for
/// a simpler workflow:
///
/// From: [Set the namespace Android documentation](https://developer.android.com/build/configure-app-module#set-namespace)
/// > For a simpler workflow, keep your namespace the same as your application
/// > ID, as they are by default.
///
/// From: [Set the application ID Android documentation](https://developer.android.com/build/configure-app-module#set-application-id):
/// > Keep the application ID the same as the namespace. The distinction
/// > between the two properties can be a bit confusing, but if you keep them
/// > the same, you have nothing to worry about.
AndroidNamespace.fromApplicationId(
AndroidApplicationId applicationId,
) : this(applicationId.value);
}
53 changes: 53 additions & 0 deletions very_good_core/hooks/lib/src/models/exceptions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'package:very_good_core_hooks/very_good_core_hooks.dart';

/// {@template very_good_core_exception}
/// An exception thrown by the `very_good_core` hooks.
/// {@endtemplate}
abstract class VeryGoodCoreHooksException implements Exception {
/// {@macro very_good_core_exception}
VeryGoodCoreHooksException({
required this.description,
required this.help,
});

/// A message describing the exception.
final String description;

/// A message describing how to resolve the exception, or signposting to
/// additional resources.
final String help;

@override
String toString() => '''
[$VeryGoodCoreHooksException] $description.

$help
''';
}

/// {@template InvalidAndroidApplicationIdFormat}
/// An exception thrown when an invalid Android application ID format is
/// given.
/// {@endtemplate}
class InvalidAndroidApplicationIdFormat extends VeryGoodCoreHooksException {
/// {@macro InvalidAndroidApplicationIdFormat}
InvalidAndroidApplicationIdFormat(AndroidApplicationId applicationId)
: super(
description:
'''An invalid Android application ID (${applicationId.value}) format was provided.''',
help: '''
Try adjusting your Android application ID (${applicationId.value}) to match the following format:

* It must have at least two segments (one or more dots).
* Each segment must start with a letter.
* All characters must be alphanumeric or an underscore [a-zA-Z0-9_].

Although the application ID looks like a traditional Kotlin or Java
package name, the naming rules for the application ID are a bit more
restrictive.

For more information, see the "Set the application ID" Android documentation:
* https://developer.android.com/build/configure-app-module#set-application-id.
''',
);
}
Loading
Loading