[flutter_tools] Add namespace getter in Android project; use namespace as fallback (#121416)
[flutter_tools] Add namespace getter in Android project; use namespace as fallback
This commit is contained in:
parent
06206c2f3a
commit
57171a3fef
@ -171,7 +171,10 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag
|
|||||||
logger.printError('Please check ${manifest.path} for errors.');
|
logger.printError('Please check ${manifest.path} for errors.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final String? packageId = manifests.first.getAttribute('package');
|
|
||||||
|
// Starting from AGP version 7.3, the `package` attribute in Manifest.xml
|
||||||
|
// can be replaced with the `namespace` attribute under the `android` section in `android/app/build.gradle`.
|
||||||
|
final String? packageId = manifests.first.getAttribute('package') ?? androidProject.namespace;
|
||||||
|
|
||||||
String? launchActivity;
|
String? launchActivity;
|
||||||
for (final XmlElement activity in document.findAllElements('activity')) {
|
for (final XmlElement activity in document.findAllElements('activity')) {
|
||||||
|
@ -424,6 +424,7 @@ class AndroidProject extends FlutterProjectPlatform {
|
|||||||
@override
|
@override
|
||||||
String get pluginConfigKey => AndroidPlugin.kConfigKey;
|
String get pluginConfigKey => AndroidPlugin.kConfigKey;
|
||||||
|
|
||||||
|
static final RegExp _androidNamespacePattern = RegExp('android {[\\S\\s]+namespace[\\s]+[\'"](.+)[\'"]');
|
||||||
static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s+[\'"](.*)[\'"]\\s*\$');
|
static final RegExp _applicationIdPattern = RegExp('^\\s*applicationId\\s+[\'"](.*)[\'"]\\s*\$');
|
||||||
static final RegExp _kotlinPluginPattern = RegExp('^\\s*apply plugin\\:\\s+[\'"]kotlin-android[\'"]\\s*\$');
|
static final RegExp _kotlinPluginPattern = RegExp('^\\s*apply plugin\\:\\s+[\'"]kotlin-android[\'"]\\s*\$');
|
||||||
static final RegExp _groupPattern = RegExp('^\\s*group\\s+[\'"](.*)[\'"]\\s*\$');
|
static final RegExp _groupPattern = RegExp('^\\s*group\\s+[\'"](.*)[\'"]\\s*\$');
|
||||||
@ -486,9 +487,15 @@ class AndroidProject extends FlutterProjectPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
File get appManifestFile {
|
File get appManifestFile {
|
||||||
return isUsingGradle
|
if(isUsingGradle) {
|
||||||
? globals.fs.file(globals.fs.path.join(hostAppGradleRoot.path, 'app', 'src', 'main', 'AndroidManifest.xml'))
|
return hostAppGradleRoot
|
||||||
: hostAppGradleRoot.childFile('AndroidManifest.xml');
|
.childDirectory('app')
|
||||||
|
.childDirectory('src')
|
||||||
|
.childDirectory('main')
|
||||||
|
.childFile('AndroidManifest.xml');
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostAppGradleRoot.childFile('AndroidManifest.xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
File get gradleAppOutV1File => gradleAppOutV1Directory.childFile('app-debug.apk');
|
File get gradleAppOutV1File => gradleAppOutV1Directory.childFile('app-debug.apk');
|
||||||
@ -512,6 +519,19 @@ class AndroidProject extends FlutterProjectPlatform {
|
|||||||
return firstMatchInFile(gradleFile, _applicationIdPattern)?.group(1);
|
return firstMatchInFile(gradleFile, _applicationIdPattern)?.group(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the namespace for newer Android projects,
|
||||||
|
/// which replaces the `package` attribute in the Manifest.xml.
|
||||||
|
String? get namespace {
|
||||||
|
final File gradleFile = hostAppGradleRoot.childDirectory('app').childFile('build.gradle');
|
||||||
|
|
||||||
|
if (!gradleFile.existsSync()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// firstMatchInFile() reads per line but `_androidNamespacePattern` matches a multiline pattern.
|
||||||
|
return _androidNamespacePattern.firstMatch(gradleFile.readAsStringSync())?.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
String? get group {
|
String? get group {
|
||||||
final File gradleFile = hostAppGradleRoot.childFile('build.gradle');
|
final File gradleFile = hostAppGradleRoot.childFile('build.gradle');
|
||||||
return firstMatchInFile(gradleFile, _groupPattern)?.group(1);
|
return firstMatchInFile(gradleFile, _groupPattern)?.group(1);
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
import 'package:archive/archive.dart';
|
import 'package:archive/archive.dart';
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:file_testing/file_testing.dart';
|
import 'package:file_testing/file_testing.dart';
|
||||||
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||||
import 'package:flutter_tools/src/android/android_studio.dart';
|
import 'package:flutter_tools/src/android/android_studio.dart';
|
||||||
|
import 'package:flutter_tools/src/android/application_package.dart';
|
||||||
import 'package:flutter_tools/src/android/gradle.dart';
|
import 'package:flutter_tools/src/android/gradle.dart';
|
||||||
import 'package:flutter_tools/src/android/gradle_errors.dart';
|
import 'package:flutter_tools/src/android/gradle_errors.dart';
|
||||||
import 'package:flutter_tools/src/android/gradle_utils.dart';
|
import 'package:flutter_tools/src/android/gradle_utils.dart';
|
||||||
@ -14,6 +16,8 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
|||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
import 'package:flutter_tools/src/base/platform.dart';
|
||||||
|
import 'package:flutter_tools/src/base/process.dart';
|
||||||
|
import 'package:flutter_tools/src/base/user_messages.dart';
|
||||||
import 'package:flutter_tools/src/build_info.dart';
|
import 'package:flutter_tools/src/build_info.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:flutter_tools/src/project.dart';
|
import 'package:flutter_tools/src/project.dart';
|
||||||
@ -23,6 +27,7 @@ import 'package:test/fake.dart';
|
|||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
import '../../src/fake_process_manager.dart';
|
import '../../src/fake_process_manager.dart';
|
||||||
|
import '../../src/fakes.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('gradle build', () {
|
group('gradle build', () {
|
||||||
@ -724,6 +729,64 @@ void main() {
|
|||||||
AndroidStudio: () => FakeAndroidStudio(),
|
AndroidStudio: () => FakeAndroidStudio(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('Uses namespace attribute if manifest lacks a package attribute', () async {
|
||||||
|
final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory);
|
||||||
|
final AndroidSdk sdk = FakeAndroidSdk();
|
||||||
|
|
||||||
|
fileSystem.directory(project.android.hostAppGradleRoot)
|
||||||
|
.childFile('build.gradle')
|
||||||
|
.createSync(recursive: true);
|
||||||
|
|
||||||
|
fileSystem.directory(project.android.hostAppGradleRoot)
|
||||||
|
.childDirectory('app')
|
||||||
|
.childFile('build.gradle')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync(
|
||||||
|
'''
|
||||||
|
apply from: irrelevant/flutter.gradle
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace 'com.example.foo'
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
|
||||||
|
fileSystem.directory(project.android.hostAppGradleRoot)
|
||||||
|
.childDirectory('app')
|
||||||
|
.childDirectory('src')
|
||||||
|
.childDirectory('main')
|
||||||
|
.childFile('AndroidManifest.xml')
|
||||||
|
..createSync(recursive: true)
|
||||||
|
..writeAsStringSync(r'''
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<application
|
||||||
|
android:label="namespacetest"
|
||||||
|
android:name="${applicationName}"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
|
''');
|
||||||
|
|
||||||
|
final AndroidApk? androidApk = await AndroidApk.fromAndroidProject(
|
||||||
|
project.android,
|
||||||
|
androidSdk: sdk,
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: logger,
|
||||||
|
processManager: processManager,
|
||||||
|
processUtils: ProcessUtils(processManager: processManager, logger: logger),
|
||||||
|
userMessages: UserMessages(),
|
||||||
|
buildInfo: const BuildInfo(BuildMode.debug, null, treeShakeIcons: false),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(androidApk?.id, 'com.example.foo');
|
||||||
|
});
|
||||||
|
|
||||||
testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAar is false", () async {
|
testUsingContext("doesn't indicate how to consume an AAR when printHowToConsumeAar is false", () async {
|
||||||
final AndroidGradleBuilder builder = AndroidGradleBuilder(
|
final AndroidGradleBuilder builder = AndroidGradleBuilder(
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user