addFeature method
Adds a uses-feature tag to the AndroidManifest.xml file.
Implementation
OperationResult addFeature(String featureName, {bool required = true}) {
final manifestFile = File(_manifestPath);
if (!manifestFile.existsSync()) {
return const Failure(
'Could not find AndroidManifest.xml. '
'Are you in a Flutter project root directory?',
);
}
final fullFeature = featureName.contains('.')
? featureName
: 'android.hardware.$featureName';
try {
final content = manifestFile.readAsStringSync();
final document = XmlDocument.parse(content);
final manifest = document.rootElement;
if (manifest.name.local != 'manifest') {
return const Failure(
'Invalid AndroidManifest.xml: root element is not <manifest>.',
);
}
const androidNs = 'http://schemas.android.com/apk/res/android';
final existingFeatures = manifest.findAllElements('uses-feature');
for (final feature in existingFeatures) {
final nameAttr = feature.getAttribute('name', namespace: androidNs) ??
feature.getAttribute('android:name');
if (nameAttr == fullFeature) {
return Success('Feature $fullFeature already exists.');
}
}
final featureElement = XmlElement(
XmlName('uses-feature'),
[
XmlAttribute(XmlName('android:name'), fullFeature),
XmlAttribute(XmlName('android:required'), required.toString()),
],
);
final children = manifest.children.toList();
int insertIndex = 0;
for (int i = 0; i < children.length; i++) {
final child = children[i];
if (child is XmlElement) {
if (child.name.local == 'uses-permission' ||
child.name.local == 'uses-feature') {
insertIndex = i + 1;
}
}
}
if (insertIndex == 0) {
for (int i = 0; i < children.length; i++) {
if (children[i] is XmlElement &&
(children[i] as XmlElement).name.local == 'application') {
insertIndex = i;
break;
}
}
}
manifest.children.insert(insertIndex, XmlText('\n '));
manifest.children.insert(insertIndex + 1, featureElement);
final output = document.toXmlString(pretty: true, indent: ' ');
manifestFile.writeAsStringSync(output);
return Success(
'Successfully added feature: $fullFeature (required: $required)');
} on XmlParserException catch (e) {
return Failure('Failed to parse AndroidManifest.xml: ${e.message}');
} on FileSystemException catch (e) {
return Failure('Failed to update AndroidManifest.xml: ${e.message}');
}
}