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

feature: add support for appcast ABI filtering #347

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 11 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this file to be in this repo.

<projectDescription>
<name>upgrader</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>
2 changes: 2 additions & 0 deletions .settings/org.eclipse.core.resources.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this file to be in this repo.

encoding/<project>=UTF-8
2 changes: 2 additions & 0 deletions .settings/org.eclipse.core.runtime.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this file to be in this repo.

line.separator=\n
2 changes: 1 addition & 1 deletion example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import url_launcher_macos

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}
25 changes: 22 additions & 3 deletions lib/src/appcast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Appcast {
List<AppcastItem>? items;

String? osVersionString;
String? deviceAbi;

/// Returns the latest critical item in the Appcast.
AppcastItem? bestCriticalItem() {
Expand All @@ -51,7 +52,8 @@ class Appcast {
items!.forEach((AppcastItem item) {
if (item.hostSupportsItem(
osVersion: osVersionString,
currentPlatform: upgraderOS.current) &&
currentPlatform: upgraderOS.current,
deviceAbi: deviceAbi) &&
item.isCriticalUpdate) {
if (bestItem == null) {
bestItem = item;
Expand Down Expand Up @@ -81,7 +83,9 @@ class Appcast {
AppcastItem? bestItem;
items!.forEach((AppcastItem item) {
if (item.hostSupportsItem(
osVersion: osVersionString, currentPlatform: upgraderOS.current)) {
osVersion: osVersionString,
currentPlatform: upgraderOS.current,
deviceAbi: deviceAbi)) {
if (bestItem == null) {
bestItem = item;
} else {
Expand Down Expand Up @@ -116,6 +120,7 @@ class Appcast {
/// Parse the Appcast from XML string.
Future<List<AppcastItem>?> parseAppcastItems(String contents) async {
osVersionString = await upgraderDevice.getOsVersionString(upgraderOS);
deviceAbi = await upgraderDevice.getPreferredAbi(upgraderOS);
return parseItemsFromXMLString(contents);
}

Expand Down Expand Up @@ -144,6 +149,7 @@ class Appcast {
String? maximumSystemVersion;
String? minimumSystemVersion;
String? osString;
String? abi;
String? releaseNotesLink;
final tags = <String>[];
String? newVersion;
Expand All @@ -168,6 +174,9 @@ class Appcast {
} else if (attribute.name.toString() ==
AppcastConstants.AttributeURL) {
fileURL = attribute.value;
} else if (attribute.name.toString() ==
AppcastConstants.AttributeAbi) {
abi = attribute.value;
}
});
} else if (name == AppcastConstants.ElementMaximumSystemVersion) {
Expand Down Expand Up @@ -209,6 +218,7 @@ class Appcast {
maximumSystemVersion: maximumSystemVersion,
minimumSystemVersion: minimumSystemVersion,
osString: osString,
abi: abi,
releaseNotesURL: releaseNotesLink,
tags: tags,
fileURL: fileURL,
Expand Down Expand Up @@ -237,6 +247,7 @@ class AppcastItem {
final int? contentLength;
final String? versionString;
final String? osString;
final String? abi;
final String? displayVersionString;
final String? infoURL;
final List<String>? tags;
Expand All @@ -252,6 +263,7 @@ class AppcastItem {
this.contentLength,
this.versionString,
this.osString,
this.abi,
this.displayVersionString,
this.infoURL,
this.tags,
Expand All @@ -264,7 +276,8 @@ class AppcastItem {
: tags!.contains(AppcastConstants.ElementCriticalUpdate);

/// Does the host support this item? If so is [osVersion] supported?
bool hostSupportsItem({String? osVersion, required String currentPlatform}) {
bool hostSupportsItem(
{String? osVersion, required String currentPlatform, String? deviceAbi}) {
assert(currentPlatform.isNotEmpty);
bool supported = true;
if (osString != null && osString!.isNotEmpty) {
Expand All @@ -273,6 +286,11 @@ class AppcastItem {
supported = platformEnum.toLowerCase() == currentPlatform.toLowerCase();
}

// check ABI if present
if (supported && deviceAbi != null) {
supported = (abi == null || deviceAbi == abi);
}

if (supported && osVersion != null && osVersion.isNotEmpty) {
Version osVersionValue;
try {
Expand Down Expand Up @@ -316,6 +334,7 @@ class AppcastConstants {
'sparkle:shortVersionString';
static const String AttributeVersion = 'sparkle:version';
static const String AttributeOsType = 'sparkle:os';
static const String AttributeAbi = 'abi';

static const String ElementCriticalUpdate = 'sparkle:criticalUpdate';
static const String ElementDeltas = 'sparkle:deltas';
Expand Down
18 changes: 17 additions & 1 deletion lib/src/upgrader_device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,30 @@ class UpgraderDevice {

return osVersionString;
}

/// Returns preferred ABI supported by the OS, if any. Currently, Android only.
Future<String?> getPreferredAbi(UpgraderOS upgraderOS) async {
final deviceInfo = DeviceInfoPlugin();
if (upgraderOS.isAndroid) {
final androidInfo = await deviceInfo.androidInfo;
final abiList = androidInfo.supportedAbis;
return abiList.isNotEmpty ? abiList.first : null;
} else {
return null;
}
}
}

class MockUpgraderDevice extends UpgraderDevice {
MockUpgraderDevice({this.osVersionString = ''});
MockUpgraderDevice({this.osVersionString = '', this.deviceAbi});

final String osVersionString;
final String? deviceAbi;

@override
Future<String?> getOsVersionString(UpgraderOS upgraderOS) async =>
osVersionString;

@override
Future<String?> getPreferredAbi(UpgraderOS upgraderOS) async => deviceAbi;
}
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies:
os_detect: ^2.0.1

# From Flutter Community: Provides an API for querying information about an application package.
package_info_plus: ^4.0.1
package_info_plus: ^8.0.0

# From Flutter Team: Wraps NSUserDefaults (on iOS) and SharedPreferences (on Android).
shared_preferences: ^2.1.1
Expand All @@ -44,6 +44,6 @@ dev_dependencies:

# From Dart Team: Mock library for Dart inspired by Mockito.
mockito: ^5.4.0
flutter_lints: ^2.0.1
flutter_lints: ^3.0.2

flutter:
27 changes: 27 additions & 0 deletions test/appcast_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,33 @@ void main() {
final bestItem = appcast.bestItem();
expect(bestItem, isNull);
});
test('Appcast ABI', () async {
var testFile = await getTestFile(filePath: 'test/testappcast-abi.xml');
// no ABI
var appcast = TestAppcast(
client: setupMockClient(),
upgraderOS: MockUpgraderOS(android: true),
upgraderDevice: MockUpgraderDevice());
await appcast.parseAppcastItemsFromFile(testFile);
var bestItem = appcast.bestItem();
expect(bestItem, isNotNull); // nothing specified so anything goes
// wrong ABI
appcast = TestAppcast(
client: setupMockClient(),
upgraderOS: MockUpgraderOS(android: true),
upgraderDevice: MockUpgraderDevice(deviceAbi: 'bogus-abi'));
await appcast.parseAppcastItemsFromFile(testFile);
bestItem = appcast.bestItem();
expect(bestItem, isNull);
// right ABI
appcast = TestAppcast(
client: setupMockClient(),
upgraderOS: MockUpgraderOS(android: true),
upgraderDevice: MockUpgraderDevice(deviceAbi: 'arm64-v8a'));
await appcast.parseAppcastItemsFromFile(testFile);
bestItem = appcast.bestItem();
expect(bestItem!.abi, 'arm64-v8a');
});
}

void validateItems(List<AppcastItem> items, Appcast appcast) {
Expand Down
7 changes: 6 additions & 1 deletion test/device_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ void main() {
final device = UpgraderDevice();
expect(await device.getOsVersionString(MockUpgraderOS(android: true)),
'1.2.3');
expect(await device.getPreferredAbi(MockUpgraderOS(android: true)),
'arm64-v8a');

// Verify invalid OS version
deviceInfo = _androidInfo(baseOS: '.');
expect(
await device.getOsVersionString(MockUpgraderOS(android: true)), isNull);
// only Android supports ABI
expect(
await device.getPreferredAbi(MockUpgraderOS(android: false)), isNull);
});

test('testing UpgraderDevice macOS', () async {
Expand Down Expand Up @@ -78,7 +83,7 @@ Map _androidInfo({required String baseOS}) {
'product': 'a',
'supported32BitAbis': ['a'],
'supported64BitAbis': ['a'],
'supportedAbis': ['a'],
'supportedAbis': ['arm64-v8a'], // also used in test
'tags': 'a',
'type': 'a',
'isPhysicalDevice': false,
Expand Down
13 changes: 13 additions & 0 deletions test/testappcast-abi.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
<channel>
<title>Releases</title>
<item>
<enclosure sparkle:version="2.1.1" sparkle:os="android" abi="armeabi-v7a"/>
</item>
<item>
<enclosure sparkle:version="2.1.1" sparkle:os="android" abi="arm64-v8a"/>
</item>
</channel>
</rss>