Compare commits

...

8 Commits

17 changed files with 270 additions and 73 deletions

View File

@ -13,6 +13,7 @@ Currently supported App sources:
- [IzzyOnDroid](https://android.izzysoft.de/) - [IzzyOnDroid](https://android.izzysoft.de/)
- [Mullvad](https://mullvad.net/en/) - [Mullvad](https://mullvad.net/en/)
- [Signal](https://signal.org/) - [Signal](https://signal.org/)
- [APKMirror](https://apkmirror.com/)
## Limitations ## Limitations
- App installs are assumed to have succeeded; failures and cancelled installs cannot be detected. - App installs are assumed to have succeeded; failures and cancelled installs cannot be detected.

View File

@ -30,16 +30,6 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

View File

@ -0,0 +1,112 @@
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/providers/source_provider.dart';
class APKMirror implements AppSource {
@override
late String host = 'apkmirror.com';
@override
String standardizeURL(String url) {
RegExp standardUrlRegEx = RegExp('^https?://$host/apk/[^/]+/[^/]+');
RegExpMatch? match = standardUrlRegEx.firstMatch(url.toLowerCase());
if (match == null) {
throw notValidURL(runtimeType.toString());
}
return url.substring(0, match.end);
}
@override
String? changeLogPageFromStandardUrl(String standardUrl) =>
'$standardUrl#whatsnew';
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async {
var originalUri = Uri.parse(apkUrl);
var res = await get(originalUri);
if (res.statusCode != 200) {
throw false;
}
var href =
parse(res.body).querySelector('.downloadButton')?.attributes['href'];
if (href == null) {
throw false;
}
var res2 = await get(Uri.parse('${originalUri.origin}$href'), headers: {
'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0'
});
if (res2.statusCode != 200) {
throw false;
}
var links = parse(res2.body)
.querySelectorAll('a')
.where((element) => element.innerHtml == 'here')
.map((e) => e.attributes['href'])
.where((element) => element != null)
.toList();
if (links.isEmpty) {
throw false;
}
return '${originalUri.origin}${links[0]}';
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async {
Response res = await get(Uri.parse('$standardUrl/feed'));
if (res.statusCode != 200) {
throw couldNotFindReleases;
}
var nextUrl = parse(res.body)
.querySelector('item')
?.querySelector('link')
?.nextElementSibling
?.innerHtml;
if (nextUrl == null) {
throw couldNotFindReleases;
}
Response res2 = await get(Uri.parse(nextUrl), headers: {
'User-Agent':
'Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0'
});
if (res2.statusCode != 200) {
throw couldNotFindReleases;
}
var html2 = parse(res2.body);
var origin = Uri.parse(standardUrl).origin;
List<String> apkUrls = html2
.querySelectorAll('.apkm-badge')
.map((e) => e.innerHtml != 'APK'
? ''
: e.previousElementSibling?.attributes['href'] ?? '')
.where((element) => element.isNotEmpty)
.map((e) => '$origin$e')
.toList();
if (apkUrls.isEmpty) {
throw noAPKFound;
}
var version = html2.querySelector('span.active.accent_color')?.innerHtml;
if (version == null) {
throw couldNotFindLatestVersion;
}
return APKDetails(version, apkUrls);
}
@override
AppNames getAppNames(String standardUrl) {
String temp = standardUrl.substring(standardUrl.indexOf('://') + 3);
List<String> names = temp.substring(temp.indexOf('/') + 1).split('/');
return AppNames(names[1], names[2]);
}
@override
List<List<GeneratedFormItem>> additionalDataFormItems = [];
@override
List<String> additionalDataDefaults = [];
@override
List<GeneratedFormItem> moreSourceSettingsFormItems = [];
}

View File

@ -23,6 +23,12 @@ class FDroid implements AppSource {
return url.substring(0, match.end); return url.substring(0, match.end);
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) => null;
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -29,6 +29,13 @@ class GitHub implements AppSource {
return creds != null && creds.isNotEmpty ? '$creds@' : ''; return creds != null && creds.isNotEmpty ? '$creds@' : '';
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) =>
'$standardUrl/releases';
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -18,6 +18,13 @@ class GitLab implements AppSource {
return url.substring(0, match.end); return url.substring(0, match.end);
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) =>
'$standardUrl/-/releases';
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -17,6 +17,12 @@ class IzzyOnDroid implements AppSource {
return url.substring(0, match.end); return url.substring(0, match.end);
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) => null;
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -17,6 +17,13 @@ class Mullvad implements AppSource {
return url.substring(0, match.end); return url.substring(0, match.end);
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) =>
'https://github.com/mullvad/mullvadvpn-app/blob/master/CHANGELOG.md';
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -12,6 +12,12 @@ class Signal implements AppSource {
return 'https://$host'; return 'https://$host';
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) => null;
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -17,6 +17,12 @@ class SourceForge implements AppSource {
return url.substring(0, match.end); return url.substring(0, match.end);
} }
@override
String? changeLogPageFromStandardUrl(String standardUrl) => null;
@override
Future<String> apkUrlPrefetchModifier(String apkUrl) async => apkUrl;
@override @override
Future<APKDetails> getLatestAPKDetails( Future<APKDetails> getLatestAPKDetails(
String standardUrl, List<String> additionalData) async { String standardUrl, List<String> additionalData) async {

View File

@ -14,7 +14,7 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
const String currentReleaseTag = const String currentReleaseTag =
'v0.5.4-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES 'v0.5.5-beta'; // KEEP THIS IN SYNC WITH GITHUB RELEASES
const String bgUpdateCheckTaskName = 'bg-update-check'; const String bgUpdateCheckTaskName = 'bg-update-check';

View File

@ -19,20 +19,27 @@ class AppPage extends StatefulWidget {
} }
class _AppPageState extends State<AppPage> { class _AppPageState extends State<AppPage> {
AppInMemory? prevApp;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var appsProvider = context.watch<AppsProvider>(); var appsProvider = context.watch<AppsProvider>();
var settingsProvider = context.watch<SettingsProvider>(); var settingsProvider = context.watch<SettingsProvider>();
var sourceProvider = SourceProvider(); getUpdate(String id) {
AppInMemory? app = appsProvider.apps[widget.appId]; appsProvider.getUpdate(id).catchError((e) {
var source = app != null ? sourceProvider.getSource(app.app.url) : null;
if (!appsProvider.areDownloadsRunning() && app != null) {
appsProvider.getUpdate(app.app.id).catchError((e) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(e.toString())), SnackBar(content: Text(e.toString())),
); );
}); });
} }
var sourceProvider = SourceProvider();
AppInMemory? app = appsProvider.apps[widget.appId];
var source = app != null ? sourceProvider.getSource(app.app.url) : null;
if (!appsProvider.areDownloadsRunning() && prevApp == null && app != null) {
prevApp = app;
getUpdate(app.app.id);
}
return Scaffold( return Scaffold(
appBar: settingsProvider.showAppWebpage ? AppBar() : null, appBar: settingsProvider.showAppWebpage ? AppBar() : null,
backgroundColor: Theme.of(context).colorScheme.surface, backgroundColor: Theme.of(context).colorScheme.surface,
@ -105,13 +112,7 @@ class _AppPageState extends State<AppPage> {
), ),
onRefresh: () async { onRefresh: () async {
if (app != null) { if (app != null) {
try { getUpdate(app.app.id);
await appsProvider.getUpdate(app.app.id);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(e.toString())),
);
}
} }
}), }),
bottomSheet: Padding( bottomSheet: Padding(
@ -244,7 +245,10 @@ class _AppPageState extends State<AppPage> {
var name = values.removeLast(); var name = values.removeLast();
changedApp.name = name; changedApp.name = name;
changedApp.additionalData = values; changedApp.additionalData = values;
appsProvider.saveApps([changedApp]); appsProvider.saveApps(
[changedApp]).then((value) {
getUpdate(changedApp.id);
});
} }
}); });
}, },

View File

@ -6,8 +6,10 @@ import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/pages/app.dart'; import 'package:obtainium/pages/app.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher_string.dart';
class AppsPage extends StatefulWidget { class AppsPage extends StatefulWidget {
const AppsPage({super.key}); const AppsPage({super.key});
@ -172,7 +174,37 @@ class AppsPageState extends State<AppsPage> {
: (sortedApps[index].app.installedVersion != null && : (sortedApps[index].app.installedVersion != null &&
sortedApps[index].app.installedVersion != sortedApps[index].app.installedVersion !=
sortedApps[index].app.latestVersion sortedApps[index].app.latestVersion
? const Text('Update Available') ? Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const Text('Update Available'),
SourceProvider()
.getSource(sortedApps[index].app.url)
.changeLogPageFromStandardUrl(
sortedApps[index].app.url) ==
null
? const SizedBox()
: GestureDetector(
onTap: () {
launchUrlString(
SourceProvider()
.getSource(
sortedApps[index].app.url)
.changeLogPageFromStandardUrl(
sortedApps[index].app.url)!,
mode:
LaunchMode.externalApplication);
},
child: const Text(
'See Changes',
style: TextStyle(
fontStyle: FontStyle.italic,
decoration:
TextDecoration.underline),
)),
],
)
: Text(sortedApps[index].app.installedVersion ?? : Text(sortedApps[index].app.installedVersion ??
'Not Installed')), 'Not Installed')),
onTap: () { onTap: () {

View File

@ -8,6 +8,7 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:install_plugin_v2/install_plugin_v2.dart';
import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/github.dart';
import 'package:obtainium/providers/notifications_provider.dart'; import 'package:obtainium/providers/notifications_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -15,7 +16,6 @@ import 'package:path_provider/path_provider.dart';
import 'package:flutter_fgbg/flutter_fgbg.dart'; import 'package:flutter_fgbg/flutter_fgbg.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:flutter_install_app/flutter_install_app.dart';
class AppInMemory { class AppInMemory {
late App app; late App app;
@ -64,6 +64,9 @@ class AppsProvider with ChangeNotifier {
} }
Future<ApkFile> downloadApp(String apkUrl, String appId) async { Future<ApkFile> downloadApp(String apkUrl, String appId) async {
apkUrl = await SourceProvider()
.getSource(apps[appId]!.app.url)
.apkUrlPrefetchModifier(apkUrl);
StreamedResponse response = StreamedResponse response =
await Client().send(Request('GET', Uri.parse(apkUrl))); await Client().send(Request('GET', Uri.parse(apkUrl)));
File downloadFile = File downloadFile =
@ -125,7 +128,7 @@ class AppsProvider with ChangeNotifier {
// If appropriate criteria are met, the update (never a fresh install) happens silently in the background // If appropriate criteria are met, the update (never a fresh install) happens silently in the background
// But even then, we don't know if it actually succeeded // But even then, we don't know if it actually succeeded
Future<void> installApk(ApkFile file) async { Future<void> installApk(ApkFile file) async {
await AppInstaller.installApk(file.file.path, actionRequired: false); await InstallPlugin.installApk(file.file.path, 'dev.imranr.obtainium');
apps[file.appId]!.app.installedVersion = apps[file.appId]!.app.installedVersion =
apps[file.appId]!.app.latestVersion; apps[file.appId]!.app.latestVersion;
await saveApps([apps[file.appId]!.app]); await saveApps([apps[file.appId]!.app]);
@ -212,17 +215,21 @@ class AppsProvider with ChangeNotifier {
return items; return items;
} }
// TODO: Remove below line if silentupdates are ever figured out
regularInstalls.addAll(silentUpdates);
silentUpdates = moveObtainiumToEnd(silentUpdates); silentUpdates = moveObtainiumToEnd(silentUpdates);
regularInstalls = moveObtainiumToEnd(regularInstalls); regularInstalls = moveObtainiumToEnd(regularInstalls);
for (var u in silentUpdates) { // TODO: Uncomment below if silentupdates are ever figured out
await installApk(u); // for (var u in silentUpdates) {
} // await installApk(u, silent: true); // Would need to add silent option
// }
if (context != null) { if (context != null) {
if (regularInstalls.isNotEmpty) { if (regularInstalls.isNotEmpty) {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
await askUserToReturnToForeground(context); await askUserToReturnToForeground(context, waitForFG: true);
} }
for (var i in regularInstalls) { for (var i in regularInstalls) {
await installApk(i); await installApk(i);
@ -307,20 +314,12 @@ class AppsProvider with ChangeNotifier {
sourceProvider.getSource(currentApp.url), sourceProvider.getSource(currentApp.url),
currentApp.url, currentApp.url,
currentApp.additionalData); currentApp.additionalData);
if (newApp.latestVersion != currentApp.latestVersion) { newApp.installedVersion = currentApp.installedVersion;
newApp.installedVersion = currentApp.installedVersion; if (currentApp.preferredApkIndex < newApp.apkUrls.length) {
if (currentApp.preferredApkIndex < newApp.apkUrls.length) { newApp.preferredApkIndex = currentApp.preferredApkIndex;
newApp.preferredApkIndex = currentApp.preferredApkIndex;
}
await saveApps([newApp]);
return newApp;
} else if ((newApp.lastUpdateCheck?.microsecondsSinceEpoch ?? 0) -
(currentApp.lastUpdateCheck?.microsecondsSinceEpoch ?? 0) >
5000000) {
currentApp.lastUpdateCheck = newApp.lastUpdateCheck;
await saveApps([currentApp]);
} }
return null; await saveApps([newApp]);
return newApp.latestVersion != currentApp.latestVersion ? newApp : null;
} }
Future<List<App>> checkUpdates({DateTime? ignoreAfter}) async { Future<List<App>> checkUpdates({DateTime? ignoreAfter}) async {
@ -428,7 +427,10 @@ class _APKPickerState extends State<APKPicker> {
Text('${widget.app.name} has more than one package:'), Text('${widget.app.name} has more than one package:'),
const SizedBox(height: 16), const SizedBox(height: 16),
...widget.app.apkUrls.map((u) => RadioListTile<String>( ...widget.app.apkUrls.map((u) => RadioListTile<String>(
title: Text(Uri.parse(u).pathSegments.last), title: Text(Uri.parse(u)
.pathSegments
.where((element) => element.isNotEmpty)
.last),
value: u, value: u,
groupValue: apkUrl, groupValue: apkUrl,
onChanged: (String? val) { onChanged: (String? val) {

View File

@ -4,6 +4,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:html/dom.dart'; import 'package:html/dom.dart';
import 'package:obtainium/app_sources/apkmirror.dart';
import 'package:obtainium/app_sources/fdroid.dart'; import 'package:obtainium/app_sources/fdroid.dart';
import 'package:obtainium/app_sources/github.dart'; import 'package:obtainium/app_sources/github.dart';
import 'package:obtainium/app_sources/gitlab.dart'; import 'package:obtainium/app_sources/gitlab.dart';
@ -136,6 +137,8 @@ abstract class AppSource {
late List<List<GeneratedFormItem>> additionalDataFormItems; late List<List<GeneratedFormItem>> additionalDataFormItems;
late List<String> additionalDataDefaults; late List<String> additionalDataDefaults;
late List<GeneratedFormItem> moreSourceSettingsFormItems; late List<GeneratedFormItem> moreSourceSettingsFormItems;
String? changeLogPageFromStandardUrl(String standardUrl);
Future<String> apkUrlPrefetchModifier(String apkUrl);
} }
abstract class MassAppSource { abstract class MassAppSource {
@ -153,7 +156,8 @@ class SourceProvider {
IzzyOnDroid(), IzzyOnDroid(),
Mullvad(), Mullvad(),
Signal(), Signal(),
SourceForge() SourceForge(),
APKMirror()
]; ];
// Add more mass source classes here so they are available via the service // Add more mass source classes here so they are available via the service

View File

@ -7,7 +7,7 @@ packages:
name: animations name: animations
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "2.0.7"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -71,6 +71,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.16.0" version: "1.16.0"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -105,42 +112,42 @@ packages:
name: device_info_plus name: device_info_plus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.2" version: "5.0.5"
device_info_plus_linux: device_info_plus_linux:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_linux name: device_info_plus_linux
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "4.0.2"
device_info_plus_macos: device_info_plus_macos:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_macos name: device_info_plus_macos
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "4.0.2"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_platform_interface name: device_info_plus_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "4.0.1"
device_info_plus_web: device_info_plus_web:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_web name: device_info_plus_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.0" version: "4.0.2"
device_info_plus_windows: device_info_plus_windows:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_windows name: device_info_plus_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.1.0" version: "5.0.2"
dynamic_color: dynamic_color:
dependency: "direct main" dependency: "direct main"
description: description:
@ -188,13 +195,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0" version: "0.2.0"
flutter_install_app:
dependency: "direct main"
description:
name: flutter_install_app
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -215,7 +215,7 @@ packages:
name: flutter_local_notifications name: flutter_local_notifications
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "11.0.1" version: "12.0.0"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -282,6 +282,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.2.0" version: "3.2.0"
install_plugin_v2:
dependency: "direct main"
description:
name: install_plugin_v2
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
js: js:
dependency: transitive dependency: transitive
description: description:
@ -400,7 +407,7 @@ packages:
name: permission_handler name: permission_handler
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "10.0.2" version: "10.1.0"
permission_handler_android: permission_handler_android:
dependency: transitive dependency: transitive
description: description:
@ -414,21 +421,21 @@ packages:
name: permission_handler_apple name: permission_handler_apple
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "9.0.4" version: "9.0.6"
permission_handler_platform_interface: permission_handler_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_platform_interface name: permission_handler_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.8.0" version: "3.9.0"
permission_handler_windows: permission_handler_windows:
dependency: transitive dependency: transitive
description: description:
name: permission_handler_windows name: permission_handler_windows
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.0" version: "0.1.1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -470,7 +477,7 @@ packages:
name: share_plus name: share_plus
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.4.0" version: "4.5.3"
share_plus_linux: share_plus_linux:
dependency: transitive dependency: transitive
description: description:
@ -491,14 +498,14 @@ packages:
name: share_plus_platform_interface name: share_plus_platform_interface
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.3" version: "3.1.1"
share_plus_web: share_plus_web:
dependency: transitive dependency: transitive
description: description:
name: share_plus_web name: share_plus_web
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.1" version: "3.1.0"
share_plus_windows: share_plus_windows:
dependency: transitive dependency: transitive
description: description:
@ -699,7 +706,7 @@ packages:
name: webview_flutter_android name: webview_flutter_android
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.10.3" version: "2.10.4"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 0.5.4+25 # When changing this, update the tag in main() accordingly version: 0.5.5+26 # When changing this, update the tag in main() accordingly
environment: environment:
sdk: '>=2.19.0-79.0.dev <3.0.0' sdk: '>=2.19.0-79.0.dev <3.0.0'
@ -38,7 +38,7 @@ dependencies:
cupertino_icons: ^1.0.5 cupertino_icons: ^1.0.5
path_provider: ^2.0.11 path_provider: ^2.0.11
flutter_fgbg: ^0.2.0 # Try removing reliance on this flutter_fgbg: ^0.2.0 # Try removing reliance on this
flutter_local_notifications: ^11.0.1 flutter_local_notifications: ^12.0.0
provider: ^6.0.3 provider: ^6.0.3
http: ^0.13.5 http: ^0.13.5
webview_flutter: ^3.0.4 webview_flutter: ^3.0.4
@ -49,10 +49,10 @@ dependencies:
url_launcher: ^6.1.5 url_launcher: ^6.1.5
permission_handler: ^10.0.0 permission_handler: ^10.0.0
fluttertoast: ^8.0.9 fluttertoast: ^8.0.9
device_info_plus: ^4.1.2 device_info_plus: ^5.0.5
file_picker: ^5.1.0 file_picker: ^5.1.0
animations: ^2.0.4 animations: ^2.0.4
flutter_install_app: ^1.3.0 install_plugin_v2: ^1.0.0
share_plus: ^4.4.0 share_plus: ^4.4.0