Compare commits

..

63 Commits

Author SHA1 Message Date
Imran
3ebbd2a4a5 Merge pull request #2033 from ImranR98/dev
Bugfix: GitHub fallback option was broken (#2032)
2024-12-12 11:05:30 -05:00
Imran Remtulla
82207a1b3b Increment version 2024-12-12 11:04:46 -05:00
Imran Remtulla
2ec5c7db11 Bugfix: GitHub fallback option was broken (#2032) 2024-12-12 11:04:31 -05:00
Imran
ab949af700 Merge pull request #2031 from ImranR98/dev
Hardcode Flutter version in GitHub action for now (until new Flutter works)
2024-12-12 04:02:41 -05:00
Imran Remtulla
5c9a35c4f0 Hardcode Flutter version in GitHub action for now (until new Flutter works) 2024-12-12 04:01:59 -05:00
Imran
8651f58744 Merge pull request #2030 from ImranR98/dev
- Avoid OS version reconciliation for pseudo-versioned apps (#2023)
- When importing configs via link, don't show dialog twice
- GitHub - do not use filtered asset release dates (#2012)
2024-12-12 03:53:27 -05:00
Imran Remtulla
d93798a8df Increment version 2024-12-12 03:52:10 -05:00
Imran Remtulla
0822f991ff Remove unused function 2024-12-12 03:34:47 -05:00
Imran Remtulla
fde63a0f05 GitHub - do not use filtered asset release dates (#2012) 2024-12-12 03:27:17 -05:00
Imran Remtulla
523e1151b2 When importing configs via link, don't show dialog twice 2024-12-12 02:58:01 -05:00
Imran Remtulla
d5d6825ed9 Avoid OS version reconciliation for pseudo-versioned apps (#2023) 2024-12-12 02:40:04 -05:00
Imran
79c4d3b9fe Merge pull request #2026 from summoner001/main
Update hu.json
2024-12-12 02:21:19 -05:00
Imran Remtulla
d6b99b903f Prevent pseudo-versioning method from changing on load (#2022) 2024-12-12 02:20:56 -05:00
summoner001
335752ee7c Update hu.json
Correcting hungarian translation
2024-12-10 15:55:12 +01:00
Imran
e5afe75213 Merge pull request #2021 from ImranR98/dev
Catch errors when running JSON compat mods - app breaking bug (#2015, #2019)
2024-12-09 17:21:40 -05:00
Imran Remtulla
0df1c1c512 Increment version 2024-12-09 17:21:00 -05:00
Imran Remtulla
bd2ac73b9f Catch errors when running JSON compat mods (#2015, #2019) 2024-12-09 17:18:25 -05:00
Imran Remtulla
26b5a2d976 Catch errors when running JSON compat mods (#2015, #2019) 2024-12-09 17:04:49 -05:00
Imran
c0968e8991 Merge pull request #2008 from ImranR98/dev
- Fix broken "Download Asset" function for HTML source (#1998)
- Add "refresh before download" (#1943)
- Remove WhatsApp, VLC, and Telegram App sources - no longer needed as HTML source sufficient (#1943)
2024-12-08 16:41:24 -05:00
Imran Remtulla
243b1eb2ac Update packages, increment version 2024-12-08 16:39:26 -05:00
Imran Remtulla
c6c61d1c83 Merge remote-tracking branch 'origin/main' into dev 2024-12-08 16:37:08 -05:00
Imran
f207967411 Merge pull request #1995 from ygxbnet/patch-2
Update zh.json
2024-12-08 16:36:56 -05:00
Imran Remtulla
29bb5cc8cd Removed Telegram App 2024-12-08 16:36:46 -05:00
Imran Remtulla
dbbc2ff19c Removed VLC (#1943) 2024-12-08 16:21:36 -05:00
Imran Remtulla
c012b016f9 Add "refresh before download" + remove WhatsApp (#1943) 2024-12-08 15:58:44 -05:00
Imran Remtulla
22815b8209 Minor bug 2024-12-08 14:53:31 -05:00
Imran Remtulla
619d4f1a51 Fix broken "Download Asset" function for HTML source (#1998) 2024-12-08 13:47:32 -05:00
YGXB_net
50e8929763 Update zh.json 2024-11-30 21:49:58 +08:00
Imran
0e2a0b65ec Merge pull request #1990 from ImranR98/dev
- Improved XAPK Support (#682)
- Custom user-agent for APKMirror (as per feedback in #1973)
- Minor change to German translation (#1986)
2024-11-23 16:31:46 -05:00
Imran Remtulla
5b79f399d1 Minor change to German translation (#1986) 2024-11-23 16:29:10 -05:00
Imran Remtulla
2961d5ac17 Merge remote-tracking branch 'origin/main' into dev 2024-11-23 16:27:21 -05:00
Imran Remtulla
4af4160aaa Increment version 2024-11-23 16:27:11 -05:00
Imran Remtulla
327f73cc9e More changes for XAPK support (#682) 2024-11-23 16:26:11 -05:00
Imran Remtulla
e82170fec6 Improved XAPK Support (#682) 2024-11-23 16:05:02 -05:00
Imran Remtulla
8922b1c048 Custom user-agent for APKMirror (as per feedback in #1973) 2024-11-23 15:26:58 -05:00
Imran
e9550c6ff0 Merge pull request #1980 from Hamster45105/wiki-links
Update wiki links
2024-11-23 01:53:07 -05:00
Hamish
890c3682c4 Update wiki links 2024-11-23 17:17:04 +11:00
Imran
a2c38968e1 Merge pull request #1977 from summoner001/main
Update hu.json
2024-11-15 13:14:29 -05:00
summoner001
a9c3ee4c54 Update hu.json
Correcting translation.
2024-11-15 14:34:01 +01:00
Imran Remtulla
36db226024 README updates
Signed-off-by: Imran Remtulla <contact@imranr.dev>
2024-11-14 21:42:25 -05:00
Imran
6fbdf62afa Merge pull request #1975 from ImranR98/dev
Bugfixes for the "download release assets" button (#1968)
2024-11-14 21:34:36 -05:00
Imran Remtulla
9344ebbb06 Upgrade Flutter + packages, increment version 2024-11-14 21:31:47 -05:00
Imran Remtulla
51b66ab983 Merge remote-tracking branch 'origin/main' into dev 2024-11-14 21:31:17 -05:00
Imran Remtulla
7f2a9b6fa5 Bugfix for "download release assets" (#1968) 2024-11-14 21:21:32 -05:00
Imran Remtulla
ac6bc4d786 Bugfix in "download release assets" button (#1968) 2024-11-14 20:50:06 -05:00
Imran
acd30b516c Merge pull request #1972 from DwainZwerg/patch-1
Update README.md
2024-11-14 20:23:41 -05:00
Imran
5bc9234101 Merge pull request #1965 from bluefly000/japanese-translation
Update ja.json
2024-11-14 20:23:28 -05:00
Imran
80d15f5232 Merge pull request #1964 from summoner001/main
update hu.json
2024-11-14 20:23:15 -05:00
DwainZwerg
eb7c2a9fc4 Update README.md 2024-11-14 15:04:14 +01:00
DwainZwerg
40175468b2 Update README.md
Add list of all repositories
2024-11-14 15:01:48 +01:00
bluefly000
814b5a71bd Update ja.json 2024-11-11 14:47:17 +09:00
bluefly000
38a1e43116 Update ja.json 2024-11-11 14:27:20 +09:00
summoner001
5064b78c79 update hu.json 2024-11-10 18:42:08 +01:00
summoner001
767350e4e3 update hu.json 2024-11-10 18:39:41 +01:00
Imran
4caae51904 Merge pull request #1962 from ImranR98/dev
- Uptodown - fix broken web scraping logic (#1956)
- Add signature info to README (#1957)
2024-11-10 02:49:22 -05:00
Imran Remtulla
83616b7a79 Upgrade packages, increment version 2024-11-10 02:46:25 -05:00
Imran Remtulla
52b2d0868c Add signature info to README (#1957) 2024-11-10 02:42:26 -05:00
Imran Remtulla
94f629859e Merge remote-tracking branch 'origin/main' into dev 2024-11-10 02:27:37 -05:00
Imran Remtulla
773d3455ae Uptodown - fix broken web scraping logic (#1956) 2024-11-10 02:27:00 -05:00
Imran
919ab16528 Merge pull request #1948 from CertainBot/main
Update es.json
2024-11-09 14:55:53 -05:00
Imran
268b89eaf6 Merge pull request #1945 from Kevinr99089/main
Correction of long translations (French)
2024-11-09 14:55:43 -05:00
CertainBot
9c9a264e39 Update es.json
- Minor changes

- Cambios menores
2024-11-03 13:06:48 +00:00
Kévin
e1e612455a Correction of long translations (French)
- The previous correction was still too long, so I corrected it again.
- Line 317: "Configuration d'applis communautaire" changed by "Appli communautaires"
- translation suggested by @peternmuller
2024-11-02 23:26:29 +01:00
43 changed files with 367 additions and 362 deletions

View File

@@ -15,6 +15,9 @@ jobs:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.24.5
- uses: actions/setup-java@v4
with:
distribution: 'temurin' # See 'Supported distributions' for available options

View File

@@ -7,10 +7,12 @@ Get Android app updates straight from the source.
Obtainium allows you to install and update apps directly from their releases pages, and receive notifications when new releases are made available.
More info:
- [Obtainium/wiki](https://github.com/ImranR98/Obtainium/wiki)
- [Obtainium Wiki](https://wiki.obtainium.imranr.dev/) ([repository](https://github.com/ImranR98/Obtainium-Wiki))
- [AppVerifier](https://github.com/soupslurpr/AppVerifier) - App verification tool (recommended, integrates with Obtainium)
- [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev/) - Crowdsourced app configurations
- [apps.obtainium.imranr.dev](https://apps.obtainium.imranr.dev/) - Crowdsourced app configurations ([repository](https://github.com/ImranR98/apps.obtainium.imranr.dev))
- [Side Of Burritos - You should use this instead of F-Droid | How to use app RSS feed](https://youtu.be/FFz57zNR_M0) - Original motivation for this app
- [Website](https://obtainium.imranr.dev) ([repository](https://github.com/ImranR98/obtainium.imranr.dev))
- [Source code](https://github.com/ImranR98/Obtainium)
Currently supported App sources:
- Open Source - General:
@@ -29,11 +31,7 @@ Currently supported App sources:
- [Tencent App Store](https://sj.qq.com/)
- Jenkins Jobs
- [APKMirror](https://apkmirror.com/) (Track-Only)
- Open Source - App-Specific:
- [VLC](https://videolan.org/)
- Other - App-Specific:
- [WhatsApp](https://whatsapp.com)
- [Telegram App](https://telegram.org)
- [Neutron Code](https://neutroncode.com)
- Direct APK Link
- "HTML" (Fallback): Any other URL that returns an HTML page with links to APK files
@@ -58,7 +56,11 @@ Or, contribute some configurations to the website by creating a PR at [this repo
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/dev.imranr.obtainium.fdroid/)
[PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index)
Verification info:
- Package ID: `dev.imranr.obtainium`
- SHA-256 Hash of Signing Certificate: `B3:53:60:1F:6A:1D:5F:D6:60:3A:E2:F5:0B:E8:0C:F3:01:36:7B:86:B6:AB:8B:1F:66:24:3D:A9:6C:D5:73:62`
- Note: The above signature is also valid for the F-Droid flavour of Obtainium, thanks to [reproducible builds](https://f-droid.org/docs/Reproducible_Builds/).
- [PGP Public Key](https://keyserver.ubuntu.com/pks/lookup?search=contact%40imranr.dev&fingerprint=on&op=index) (to verify APK hashes)
## Limitations
- For some sources, data is gathered using Web scraping and can easily break due to changes in website design. In such cases, more reliable methods may be unavailable.

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "Želite li ukloniti aplikaciju?",
"other": "Želite li ukloniti aplikacije?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Konfigurace aplikací s využitím crowdsourcingu",
"allowInsecure": "Povolení nezabezpečených požadavků HTTP",
"stayOneVersionBehind": "Zůstaňte o jednu verzi pozadu za nejnovější",
"refreshBeforeDownload": "Obnovení údajů o aplikaci před stažením",
"removeAppQuestion": {
"one": "Odstranit Apku?",
"other": "Odstranit Apky?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourcede app-konfigurationer",
"allowInsecure": "Tillad usikre HTTP-anmodninger",
"stayOneVersionBehind": "Forbliv én version bagud den seneste",
"refreshBeforeDownload": "Opdater app-detaljer før download",
"removeAppQuestion": {
"one": "Fjern app?",
"other": "Fjern apps?"

View File

@@ -114,7 +114,7 @@
"light": "Hell",
"followSystem": "System folgen",
"followSystemThemeExplanation": "Das Folgen des Systemthemes ist unter Android < 10 nur mit Hilfe von Drittanbieterapps möglich",
"useBlackTheme": "Pure Black Dark Theme verwenden",
"useBlackTheme": "Rein schwarzen Hintergrund verwenden",
"appSortBy": "App sortieren nach",
"authorName": "Autor/Name",
"nameAuthor": "Name/Autor",
@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App-Konfigurationen",
"allowInsecure": "Unsichere HTTP-Anfragen zulassen",
"stayOneVersionBehind": "Eine Version hinter der neuesten Version bleiben",
"refreshBeforeDownload": "App-Details vor dem Download aktualisieren",
"removeAppQuestion": {
"one": "App entfernen?",
"other": "Apps entfernen?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "Forigi la aplikaĵon?",
"other": "Forigi la aplikaĵojn?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "Remove App?",
"other": "Remove Apps?"

View File

@@ -258,10 +258,10 @@
"bgUpdatesOnWiFiOnly": "Deshabilitar las actualizaciones en segundo plano sin WiFi",
"bgUpdatesWhileChargingOnly": "Desactiva las actualizaciones en segundo plano cuando no estés cargando",
"autoSelectHighestVersionCode": "Auto selección del paquete APK con versión más reciente",
"versionExtractionRegEx": "Versión de extracción regex",
"versionExtractionRegEx": "Versión de extracción RegEx",
"trimVersionString": "Recortar cadena de versión con RegEx",
"matchGroupToUseForX": "Grupo de coincidencia a utilizar para \"{}\"",
"matchGroupToUse": "Grupo a usar para versión de extracción regex",
"matchGroupToUse": "Grupo a usar para versión de extracción RegEx",
"highlightTouchTargets": "Resaltar objetivos menos obvios",
"pickExportDir": "Directorio para exportar",
"autoExportOnChanges": "Auto exportar cuando haya cambios",
@@ -275,7 +275,7 @@
"debugMenu": "Menu Depurar",
"bgTaskStarted": "Iniciada tarea en segundo plano; revise los registros.",
"runBgCheckNow": "Ejecutar verficiación de actualizaciones en segundo plano",
"versionExtractWholePage": "Aplicar la versión de extracción regex a la página entera",
"versionExtractWholePage": "Aplicar la versión de extracción RegEx a la página entera",
"installing": "Instalando",
"skipUpdateNotifications": "No notificar sobre actualizaciones",
"updatesAvailableNotifChannel": "Actualizaciones disponibles",
@@ -310,13 +310,14 @@
"note": "Nota",
"selfHostedNote": "El desplegable «{}» puede usarse para acceder a instancias autoalojadas/personalizadas de cualquier fuente.",
"badDownload": "No se ha podido analizar el APK (incompatible o descarga parcial)",
"beforeNewInstallsShareToAppVerifier": "Compartir aplicaciones nuevas con AppVerifier (si está disponible)",
"appVerifierInstructionToast": "Comparta con AppVerifier y vuelva aquí cuando esté listo.",
"beforeNewInstallsShareToAppVerifier": "Compartir aplicaciones nuevas con AppVerifier (si está instalado)",
"appVerifierInstructionToast": "Compartir con AppVerifier y vuelver aquí cuando esté listo.",
"wiki": "Ayuda/Wiki",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (uso bajo su propia responsabilidad)",
"crowdsourcedConfigsLabel": "Crowdsourced App Configurations (use bajo su responsabilidad)",
"crowdsourcedConfigsShort": "Configuración de aplicaciones por crowdsourcing",
"allowInsecure": "Permitir peticiones HTTP inseguras",
"stayOneVersionBehind": "Mantenerse una versión por detrás de la última",
"refreshBeforeDownload": "Actualiza los datos de la aplicación antes de descargarla",
"removeAppQuestion": {
"one": "¿Eliminar aplicación?",
"other": "¿Eliminar aplicaciones?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "درخواست های HTTP ناامن را مجاز کنید",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "برنامه حذف شود؟",
"other": "برنامه ها حذف شوند؟"

View File

@@ -313,10 +313,11 @@
"beforeNewInstallsShareToAppVerifier": "Partager les nouvelles applications avec AppVerifier (si disponible)",
"appVerifierInstructionToast": "Partagez avec AppVerifier, puis revenez ici lorsque tout est prêt.",
"wiki": "Aide/Wiki",
"crowdsourcedConfigsLabel": "Configurations d'applis communautaire (à utiliser à vos risques et périls)",
"crowdsourcedConfigsShort": "Configuration d'applis communautaire",
"crowdsourcedConfigsLabel": "Configuration d'applis communautaire (à utiliser à vos risques et périls)",
"crowdsourcedConfigsShort": "Applis communautaires",
"allowInsecure": "Autoriser les requêtes HTTP non sécurisées",
"stayOneVersionBehind": "Rester à une version de la dernière",
"refreshBeforeDownload": "Actualiser les détails de l'application avant de la télécharger",
"removeAppQuestion": {
"one": "Supprimer l'application?",
"other": "Supprimer les applications?"

View File

@@ -213,7 +213,7 @@
"releaseDateAsVersion": "Használja a kiadás dátumát verzió-karakterláncként",
"releaseTitleAsVersion": "Használja a kiadás címét verzió-karakterláncként",
"releaseDateAsVersionExplanation": "Ezt a beállítást csak olyan alkalmazásoknál szabad használni, ahol a verzió-érzékelés nem működik megfelelően, de elérhető a kiadás dátuma.",
"changes": "Változások",
"changes": "Változáslista",
"releaseDate": "Kiadás dátuma",
"importFromURLsInFile": "Importálás fájlban található webcímből (pl. OPML)",
"versionDetectionExplanation": "A verzió-karakterlánc egyeztetése az rendszer által érzékelt verzióval",
@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Nem biztonságos HTTP-kérések engedélyezése",
"stayOneVersionBehind": "Maradjon egy verzióval a legújabb mögött",
"refreshBeforeDownload": "Az alkalmazás adatainak frissítése a letöltés előtt",
"removeAppQuestion": {
"one": "Eltávolítja az alkalmazást?",
"other": "Eltávolítja az alkalmazásokat?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Konfigurasi Aplikasi Crowdsourced",
"allowInsecure": "Izinkan permintaan HTTP yang tidak aman",
"stayOneVersionBehind": "Tetap satu versi di belakang versi terbaru",
"refreshBeforeDownload": "Segarkan detail aplikasi sebelum mengunduh",
"removeAppQuestion": {
"one": "Hapus aplikasi?",
"other": "Hapus aplikasi?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Configurazioni di app in crowdsourcing",
"allowInsecure": "Consentire le richieste HTTP non sicure",
"stayOneVersionBehind": "Rimanere una versione indietro rispetto alla più recente",
"refreshBeforeDownload": "Aggiornare i dettagli dell'app prima del download",
"removeAppQuestion": {
"one": "Rimuovere l'app?",
"other": "Rimuovere le app?"

View File

@@ -147,21 +147,21 @@
"noNewUpdates": "新しいアップデートはありません",
"xHasAnUpdate": "{} のアップデートが利用可能です。",
"appsUpdated": "アプリをアップデートしました",
"appsNotUpdated": "アプリケーションの更新に失敗",
"appsNotUpdated": "アプリのアップデートに失敗しました",
"appsUpdatedNotifDescription": "1つまたは複数のAppのアップデートがバックグラウンドで適用されたことをユーザーに通知する",
"xWasUpdatedToY": "{} が {} にアップデートされました",
"xWasNotUpdatedToY": "への更新に失敗しました",
"xWasNotUpdatedToY": "{} の {} へのアップデートに失敗しました",
"errorCheckingUpdates": "アップデート確認中のエラー",
"errorCheckingUpdatesNotifDescription": "バックグラウンドでのアップデート確認に失敗した際に表示される通知",
"appsRemoved": "削除されたアプリ",
"appsRemovedNotifDescription": "アプリの読み込み中にエラーが発生したため、1つまたは複数のアプリが削除されたことをユーザーに通知する",
"xWasRemovedDueToErrorY": "このエラーのため、{} は削除されました: {}",
"completeAppInstallation": "アプリのインストールを完了する",
"obtainiumMustBeOpenToInstallApps": "アプリをインストールするにはObtainiumが開いている必要があります",
"obtainiumMustBeOpenToInstallApps": "アプリをインストールするにはObtainiumを開く必要があります",
"completeAppInstallationNotifDescription": "アプリのインストールを完了するために、Obtainiumに戻る必要があります",
"checkingForUpdates": "アップデートを確認中",
"checkingForUpdatesNotifDescription": "アップデートを確認する際に表示される一時的な通知",
"pleaseAllowInstallPerm": "Obtainiumによるアプリのインストールを許可してください",
"pleaseAllowInstallPerm": "Obtainiumによるアプリのインストールを許可してください",
"trackOnly": "追跡のみ",
"errorWithHttpStatusCode": "エラー {}",
"versionCorrectionDisabled": "バージョン補正無効 (プラグインが動作していません)",
@@ -211,7 +211,7 @@
"uninstallFromDevice": "デバイスからアンインストールする",
"onlyWorksWithNonVersionDetectApps": "バージョン検出を無効にしているアプリにのみ動作します。",
"releaseDateAsVersion": "リリース日をバージョンとして使用する",
"releaseTitleAsVersion": "リリースタイトルをバージョン文字列として使用",
"releaseTitleAsVersion": "リリースタイトルをバージョンとして使用する",
"releaseDateAsVersionExplanation": "このオプションは、バージョン検出が正しく機能しないアプリで、リリース日が利用可能な場合にのみ使用する必要があります。",
"changes": "変更点",
"releaseDate": "リリース日",
@@ -256,7 +256,7 @@
"intermediateLink": "中間リンク",
"exemptFromBackgroundUpdates": "バックグラウンドアップデートを行わない (有効な場合)",
"bgUpdatesOnWiFiOnly": "WiFiを使用していない場合、バックグラウンドアップデートを無効にする",
"bgUpdatesWhileChargingOnly": "非充電時にバックグラウンド更新を無効にする",
"bgUpdatesWhileChargingOnly": "非充電時にバックグラウンドアップデートを無効にする",
"autoSelectHighestVersionCode": "最も高いバージョンコードのAPKを自動で選択する",
"versionExtractionRegEx": "バージョン抽出の正規表現",
"trimVersionString": "正規表現でバージョン文字列をトリムする",
@@ -316,7 +316,8 @@
"crowdsourcedConfigsLabel": "クラウドソーシングによるアプリの設定(利用は自己責任で)",
"crowdsourcedConfigsShort": "クラウドソーシングによるアプリの設定",
"allowInsecure": "安全でないHTTPリクエストを許可する",
"stayOneVersionBehind": "最新バージョンから1つ遅れ",
"stayOneVersionBehind": "最新バージョンから1つ前のものを使用する",
"refreshBeforeDownload": "ダウンロード前にアプリの詳細を更新する",
"removeAppQuestion": {
"one": "アプリを削除しますか?",
"other": "アプリを削除しますか?"
@@ -358,23 +359,23 @@
"other": "{n} 個のログをクリアしました (前 = {before}, 後 = {after})"
},
"xAndNMoreUpdatesAvailable": {
"one": "{} とさらに {} 個のアプリのアップデートが利用可能です。",
"one": "{} とさらに 1 個のアプリのアップデートが利用可能です。",
"other": "{} とさらに {} 個のアプリのアップデートが利用可能です。"
},
"xAndNMoreUpdatesInstalled": {
"one": "{} とさらに {} 個のアプリがアップデートされました。",
"one": "{} とさらに 1 個のアプリがアップデートされました。",
"other": "{} とさらに {} 個のアプリがアップデートされました。"
},
"xAndNMoreUpdatesFailed": {
"one": "更新に失敗しました。",
"other": "アプリのアップデートに失敗しました。"
"one": "{} とさらに 1 個のアプリのアップデートに失敗しました。",
"other": "{} とさらに {} 個のアプリのアップデートに失敗しました。"
},
"xAndNMoreUpdatesPossiblyInstalled": {
"one": "{} とさらに 1 個のアプリがアップデートされた可能性があります。",
"other": "{} とさらに {} 個のアプリがアップデートされた可能性があります。"
},
"apk": {
"one": "{}APK",
"other": "{}APK"
"one": "{} APK",
"other": "{} APK"
}
}

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "App-configuraties door menigte",
"allowInsecure": "Onveilige HTTP-verzoeken toestaan",
"stayOneVersionBehind": "Blijf een versie achter op de nieuwste",
"refreshBeforeDownload": "Vernieuw app details voor download",
"removeAppQuestion": {
"one": "App verwijderen?",
"other": "Apps verwijderen?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Baza konfiguracji",
"allowInsecure": "Zezwalaj na niezabezpieczone żądania HTTP",
"stayOneVersionBehind": "Pozostań jedną wersję w tyle za najnowszą",
"refreshBeforeDownload": "Odśwież szczegóły aplikacji przed pobraniem",
"removeAppQuestion": {
"one": "Usunąć aplikację?",
"few": "Usunąć aplikacje?",

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Configurações de aplicações com base em crowdsourcing",
"allowInsecure": "Permitir pedidos HTTP inseguros",
"stayOneVersionBehind": "Manter-se uma versão atrás da mais recente",
"refreshBeforeDownload": "Atualizar os detalhes da aplicação antes da transferência",
"removeAppQuestion": {
"one": "Remover aplicativo?",
"other": "Remover aplicativos?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Конфиги приложений с помощью краудсорсинга",
"allowInsecure": "Разрешить небезопасные HTTP-запросы",
"stayOneVersionBehind": "Не отставайте от последней версии",
"refreshBeforeDownload": "Обновляйте информацию о приложении перед загрузкой",
"removeAppQuestion": {
"one": "Удалить приложение?",
"other": "Удалить приложения?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Appkonfigurationer med hjälp av crowdsourcing",
"allowInsecure": "Tillåt osäkra HTTP-förfrågningar",
"stayOneVersionBehind": "Håll dig en version bakom den senaste",
"refreshBeforeDownload": "Uppdatera appdetaljerna före nedladdning",
"removeAppQuestion": {
"one": "Ta Bort App?",
"other": "Ta Bort Appar?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Kitle Kaynaklı Uygulama Yapılandırmaları",
"allowInsecure": "Güvensiz HTTP isteklerine izin ver",
"stayOneVersionBehind": "En son sürümün bir sürüm gerisinde kalın",
"refreshBeforeDownload": "İndirmeden önce uygulama ayrıntılarını yenileyin",
"removeAppQuestion": {
"one": "Uygulamayı Kaldır?",
"other": "Uygulamaları Kaldır?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Налаштування краудсорсингових додатків",
"allowInsecure": "Дозволити незахищені HTTP-запити",
"stayOneVersionBehind": "Залишайтеся на одну версію актуальнішою",
"refreshBeforeDownload": "Оновіть інформацію про програму перед завантаженням",
"removeAppQuestion": {
"one": "Видалити застосунок?",
"other": "Видалити застосунки?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "Gỡ ứng dụng?",
"other": "Gỡ ứng dụng?"

View File

@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "Crowdsourced App Configs",
"allowInsecure": "Allow insecure HTTP requests",
"stayOneVersionBehind": "Stay one version behind latest",
"refreshBeforeDownload": "Refresh app details before download",
"removeAppQuestion": {
"one": "移除應用程式?",
"other": "移除應用程式?"

View File

@@ -186,10 +186,10 @@
"additionalOptions": "附加选项",
"disableVersionDetection": "禁用版本检测",
"noVersionDetectionExplanation": "此选项应该仅用于无法进行版本检测的应用。",
"downloadingX": "正在下载{}",
"downloadingX": "正在下载 {}",
"downloadX": "下载 {}",
"downloadedX": "下载 {}",
"releaseAsset": "发行版附件",
"downloadedX": "下载 {}",
"releaseAsset": "发行件",
"downloadNotifDescription": "提示应用的下载进度",
"noAPKFound": "未找到 APK 文件",
"noVersionDetection": "禁用版本检测",
@@ -317,6 +317,7 @@
"crowdsourcedConfigsShort": "众包应用程序配置",
"allowInsecure": "允许不安全的 HTTP 请求",
"stayOneVersionBehind": "比最新版本晚一个版本",
"refreshBeforeDownload": "下载前刷新应用程序详细信息",
"removeAppQuestion": {
"one": "是否删除应用?",
"other": "是否删除应用?"

View File

@@ -1,5 +1,5 @@
<p>Obtainium allows you to install and update Apps directly from their releases pages, and receive notifications when new releases are made available.</p>
<p>Read the <a href="https://github.com/ImranR98/Obtainium/wiki">Wiki</a></p>
<p>Read the <a href="https://wiki.obtainium.imranr.dev/">Wiki</a></p>
<p>
<b>Currently supported App sources:</b>
</p>

View File

@@ -1,5 +1,5 @@
<p>Obtainium позволяет вам устанавливать и обновлять приложения прямо с их объявлений о выпусках и получать уведомления о новых выпусках.</p>
<p>Для деталей читайте <a href="https://github.com/ImranR98/Obtainium/wiki">Вики</a></p>
<p>Для деталей читайте <a href="https://wiki.obtainium.imranr.dev/">Вики</a></p>
<p>
<b>Поддерживаемые источники приложений:</b>
</p>

View File

@@ -5,6 +5,8 @@ import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
class APKMirror extends AppSource {
@@ -31,6 +33,16 @@ class APKMirror extends AppSource {
];
}
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) async {
return {
"User-Agent":
"Obtainium/${(await getInstalledInfo(obtainiumId))?.versionName ?? '1.0.0'}"
};
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
RegExp standardUrlRegEx = RegExp(

View File

@@ -105,11 +105,7 @@ class APKPure extends AppSource {
.map((e) => e.text.trim())
.map((t) => t == 'APKs' ? 'APK' : t) ??
[];
String type = types.isEmpty
? 'APK'
: types.length == 1
? types.first
: types.last;
String type = types.isEmpty ? 'APK' : types.first;
String? dateString = apkInfo
?.querySelector('div.info-bottom span.time')
?.text

View File

@@ -275,14 +275,15 @@ class GitHub extends AppSource {
}
}
List<MapEntry<String, String>> getReleaseAssetUrls(dynamic release) =>
findReleaseAssetUrls(dynamic release) =>
(release['assets'] as List<dynamic>?)?.map((e) {
var url = !e['name'].toString().toLowerCase().endsWith('.apk')
? (e['browser_download_url'] ?? e['url'])
: (e['url'] ?? e['browser_download_url']);
return (e['name'] != null) && (url != null)
e['final_url'] = (e['name'] != null) && (url != null)
? MapEntry(e['name'] as String, url as String)
: const MapEntry('', '');
return e;
}).toList() ??
[];
@@ -293,7 +294,9 @@ class GitHub extends AppSource {
? DateTime.parse(rel['commit']['created'])
: null;
DateTime? getNewestAssetDateFromRelease(dynamic rel) {
var t = (rel['assets'] as List<dynamic>?)
var allAssets = rel['assets'] as List<dynamic>?;
var filteredAssets = rel['filteredAssets'] as List<dynamic>?;
var t = (filteredAssets ?? allAssets)
?.map((e) {
return e?['updated_at'] != null
? DateTime.parse(e['updated_at'])
@@ -387,18 +390,37 @@ class GitHub extends AppSource {
.hasMatch(((releases[i]['body'] as String?) ?? '').trim())) {
continue;
}
var allAssetUrls = getReleaseAssetUrls(releases[i]);
List<MapEntry<String, String>> apkUrls = allAssetUrls
.where((element) => element.key.toLowerCase().endsWith('.apk'))
var allAssetsWithUrls = findReleaseAssetUrls(releases[i]);
List<MapEntry<String, String>> allAssetUrls = allAssetsWithUrls
.map((e) => e['final_url'] as MapEntry<String, String>)
.toList();
var apkAssetsWithUrls = allAssetsWithUrls
.where((element) =>
(element['final_url'] as MapEntry<String, String>)
.key
.toLowerCase()
.endsWith('.apk'))
.toList();
apkUrls = filterApks(apkUrls, additionalSettings['apkFilterRegEx'],
var filteredApkUrls = filterApks(
apkAssetsWithUrls
.map((e) => e['final_url'] as MapEntry<String, String>)
.toList(),
additionalSettings['apkFilterRegEx'],
additionalSettings['invertAPKFilter']);
if (apkUrls.isEmpty && additionalSettings['trackOnly'] != true) {
var filteredApks = apkAssetsWithUrls
.where((e) => filteredApkUrls
.where((e2) =>
e2.key == (e['final_url'] as MapEntry<String, String>).key)
.isNotEmpty)
.toList();
if (filteredApks.isEmpty && additionalSettings['trackOnly'] != true) {
continue;
}
targetRelease = releases[i];
targetRelease['apkUrls'] = apkUrls;
targetRelease['apkUrls'] = filteredApkUrls;
targetRelease['filteredAssets'] = filteredApks;
targetRelease['version'] =
additionalSettings['releaseTitleAsVersion'] == true
? nameToFilter
@@ -420,6 +442,7 @@ class GitHub extends AppSource {
throw NoReleasesError();
}
String? version = targetRelease['version'];
DateTime? releaseDate = getReleaseDateFromRelease(
targetRelease, useLatestAssetDateAsReleaseDate);
if (version == null) {

View File

@@ -7,6 +7,9 @@ import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
String ensureAbsoluteUrl(String ambiguousUrl, Uri referenceAbsoluteUrl) {
if (ambiguousUrl.startsWith('//')) {
ambiguousUrl = '${referenceAbsoluteUrl.scheme}:$ambiguousUrl';
}
try {
Uri.parse(ambiguousUrl).origin;
return ambiguousUrl;
@@ -353,7 +356,12 @@ class HTML extends AppSource {
forAPKDownload: true),
allowInsecure: additionalSettings['allowInsecure'] == true))
.toString();
return APKDetails(version, [rel].map((e) => MapEntry(e, e)).toList(),
return APKDetails(
version,
[rel]
.map((e) =>
MapEntry('${e.hashCode}-${Uri.parse(e).pathSegments.last}', e))
.toList(),
AppNames(uri.host, tr('app')));
}
}

View File

@@ -42,19 +42,16 @@ class Uptodown extends AppSource {
String? version = html.querySelector('div.version')?.innerHtml;
String? name = html.querySelector('#detail-app-name')?.innerHtml.trim();
String? author = html.querySelector('#author-link')?.innerHtml.trim();
var detailElements = html.querySelectorAll('#technical-information td');
String? appId = (detailElements.elementAtOrNull(2))?.innerHtml.trim();
String? dateStr = (detailElements.elementAtOrNull(29))?.innerHtml.trim();
var detailElements = html
.querySelectorAll('#technical-information td')
.map((e) => e.innerHtml.trim())
.where((e) => !e.startsWith('<'))
.toList();
String? appId = detailElements.elementAtOrNull(0);
String? dateStr = detailElements.elementAtOrNull(6);
String? fileId =
html.querySelector('#detail-app-name')?.attributes['data-file-id'];
String? extension = html
.querySelectorAll('td')
.where((e) => e.text.toLowerCase().trim() == 'file type')
.firstOrNull
?.nextElementSibling
?.text
.toLowerCase()
.trim();
String? extension = detailElements.elementAtOrNull(7)?.toLowerCase();
return Map.fromEntries([
MapEntry('version', version),
MapEntry('appId', appId),

View File

@@ -1,110 +0,0 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class VLC extends AppSource {
VLC() {
hosts = ['videolan.org'];
}
get dwUrlBase => 'https://get.${hosts[0]}/vlc-android/';
@override
Future<Map<String, String>?> getRequestHeaders(
Map<String, dynamic> additionalSettings,
{bool forAPKDownload = false}) async {
return {
"User-Agent":
"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"
};
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
return 'https://${hosts[0]}';
}
Future<String?> getLatestVersion(
String standardUrl, Map<String, dynamic> additionalSettings) async {
Response res = await sourceRequest(dwUrlBase, additionalSettings);
if (res.statusCode == 200) {
var dwLinks = parse(res.body)
.querySelectorAll('a')
.where((element) => element.attributes['href'] != 'last/')
.map((e) => e.attributes['href']?.split('/')[0])
.toList();
String? version = dwLinks.isNotEmpty ? dwLinks.last : null;
if (version == null) {
throw NoVersionError();
}
return version;
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
Response res = await get(
Uri.parse('https://www.videolan.org/vlc/download-android.html'));
if (res.statusCode == 200) {
var dwUrlBase = 'get.videolan.org/vlc-android';
var dwLinks = parse(res.body)
.querySelectorAll('a')
.where((element) =>
element.attributes['href']?.contains(dwUrlBase) ?? false)
.toList();
String? version = dwLinks.isNotEmpty
? dwLinks.first.attributes['href']
?.split('/')
.where((s) => s.isNotEmpty)
.last
: null;
if (version == null) {
throw NoVersionError();
}
String? targetUrl = 'https://$dwUrlBase/$version/';
var apkUrls = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
.map((e) => '${targetUrl}VLC-Android-$version-$e.apk')
.toList();
return APKDetails(
version, getApkUrlsFromUrls(apkUrls), AppNames('VideoLAN', 'VLC'));
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
Response res = await sourceRequest(apkUrl, additionalSettings);
if (res.statusCode == 200) {
String? apkUrl =
parse(res.body).querySelector('#alt_link')?.attributes['href'];
if (apkUrl == null) {
throw NoAPKError();
}
return apkUrl;
} else if (res.statusCode == 500 &&
res.body.toLowerCase().indexOf('mirror') > 0) {
var html = parse(res.body);
var err = '';
html.body?.nodes.forEach((element) {
if (element.text != null) {
err += '${element.text}\n';
}
});
err = err.trim();
if (err.isEmpty) {
err = tr('err');
}
throw ObtainiumError(err);
} else {
throw getObtainiumHttpError(res);
}
}
}

View File

@@ -1,55 +0,0 @@
import 'package:html/parser.dart';
import 'package:http/http.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/providers/source_provider.dart';
class WhatsApp extends AppSource {
WhatsApp() {
hosts = ['whatsapp.com'];
versionDetectionDisallowed = true;
}
@override
String sourceSpecificStandardizeURL(String url, {bool forSelection = false}) {
return 'https://${hosts[0]}';
}
@override
Future<String> apkUrlPrefetchModifier(String apkUrl, String standardUrl,
Map<String, dynamic> additionalSettings) async {
Response res =
await sourceRequest('$standardUrl/android', additionalSettings);
if (res.statusCode == 200) {
var targetLinks = parse(res.body)
.querySelectorAll('a')
.map((e) => e.attributes['href'] ?? '')
.where((e) => e.isNotEmpty)
.where((e) => e.contains('WhatsApp.apk'))
.toList();
if (targetLinks.isEmpty) {
throw NoAPKError();
}
return targetLinks[0];
} else {
throw getObtainiumHttpError(res);
}
}
@override
Future<APKDetails> getLatestAPKDetails(
String standardUrl,
Map<String, dynamic> additionalSettings,
) async {
// This is a CDN link that is consistent per version
// But it has query params that change constantly
Uri apkUri = Uri.parse(await apkUrlPrefetchModifier(
standardUrl, standardUrl, additionalSettings));
var unusableApkUrl = '${apkUri.origin}/${apkUri.path}';
// So we use the param-less URL is a pseudo-version to add the app and check for updates
// See #357 for why we can't scrape the version number directly
// But we re-fetch the URL again with its latest query params at the actual download time
String version = unusableApkUrl.hashCode.toString();
return APKDetails(version, getApkUrlsFromUrls([unusableApkUrl]),
AppNames('Meta', 'WhatsApp'));
}
}

View File

@@ -838,30 +838,6 @@ class AppsPageState extends State<AppsPage> {
Navigator.of(context).pop();
}
resetSelectedAppsInstallStatuses() async {
try {
var values = await showDialog(
context: context,
builder: (BuildContext ctx) {
return GeneratedFormModal(
title: tr('resetInstallStatusForSelectedAppsQuestion'),
items: const [],
initValid: true,
message: tr('installStatusOfXWillBeResetExplanation',
args: [plural('apps', selectedAppIds.length)]),
);
});
if (values != null) {
appsProvider.saveApps(selectedApps.map((e) {
e.installedVersion = null;
return e;
}).toList());
}
} finally {
Navigator.of(context).pop();
}
}
showMoreOptionsDialog() {
return showDialog(
context: context,

View File

@@ -130,13 +130,18 @@ class _HomePageState extends State<HomePage> {
// Check initial link if app was in cold state (terminated)
final appLink = await _appLinks.getInitialLink();
var initLinked = false;
if (appLink != null) {
await interpretLink(appLink);
initLinked = true;
}
// Handle link when app is in warm state (front or background)
_linkSubscription = _appLinks.uriLinkStream.listen((uri) async {
await interpretLink(uri);
if (!initLinked) {
await interpretLink(uri);
} else {
initLinked = false;
}
});
}

View File

@@ -886,7 +886,7 @@ class _SettingsPageState extends State<SettingsPage> {
),
IconButton(
onPressed: () {
launchUrlString('${settingsProvider.sourceUrl}/wiki',
launchUrlString('https://wiki.obtainium.imranr.dev/',
mode: LaunchMode.externalApplication);
},
icon: const Icon(Icons.help_outline_rounded),

View File

@@ -19,6 +19,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/io_client.dart';
import 'package:obtainium/app_sources/directAPKLink.dart';
import 'package:obtainium/app_sources/html.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/components/generated_form_modal.dart';
import 'package:obtainium/custom_errors.dart';
@@ -516,11 +518,29 @@ class AppsProvider with ChangeNotifier {
.listSync()
.where((e) => e.path.toLowerCase().endsWith('.apk'))
.toList();
FileSystemEntity? temp;
apks.removeWhere((element) {
bool res = element.uri.pathSegments.last.startsWith(app.id);
if (res) {
temp = element;
}
return res;
});
if (temp != null) {
apks = [
temp!,
...apks,
];
}
for (var i = 0; i < apks.length; i++) {
try {
newInfo = await pm.getPackageArchiveInfo(
archiveFilePath: apks.first.path);
break;
newInfo =
await pm.getPackageArchiveInfo(archiveFilePath: apks[i].path);
if (newInfo != null) {
break;
}
} catch (e) {
if (i == apks.length - 1) {
rethrow;
@@ -644,28 +664,47 @@ class AppsProvider with ChangeNotifier {
var somethingInstalled = false;
try {
MultiAppMultiError errors = MultiAppMultiError();
List<File> APKFiles = [];
for (var file in dir.extracted
.listSync(recursive: true, followLinks: false)
.whereType<File>()) {
if (file.path.toLowerCase().endsWith('.apk')) {
try {
somethingInstalled = somethingInstalled ||
await installApk(
DownloadedApk(dir.appId, file), firstTimeWithContext,
needsBGWorkaround: needsBGWorkaround,
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay);
} catch (e) {
logs.add(
'Could not install APK from XAPK \'${file.path}\': ${e.toString()}');
errors.add(dir.appId, e, appName: apps[dir.appId]?.name);
}
APKFiles.add(file);
} else if (file.path.toLowerCase().endsWith('.obb')) {
await moveObbFile(file, dir.appId);
}
}
if (somethingInstalled) {
File? temp;
APKFiles.removeWhere((element) {
bool res = element.uri.pathSegments.last.startsWith(dir.appId);
if (res) {
temp = element;
}
return res;
});
if (temp != null) {
APKFiles = [
temp!,
...APKFiles,
];
}
try {
await installApk(
DownloadedApk(dir.appId, APKFiles[0]), firstTimeWithContext,
needsBGWorkaround: needsBGWorkaround,
shizukuPretendToBeGooglePlay: shizukuPretendToBeGooglePlay,
additionalAPKs: APKFiles.sublist(1)
.map((a) => DownloadedApk(dir.appId, a))
.toList());
somethingInstalled = true;
dir.file.delete(recursive: true);
} else if (errors.idsByErrorString.isNotEmpty) {
} catch (e) {
logs.add('Could not install APKs from XAPK: ${e.toString()}');
errors.add(dir.appId, e, appName: apps[dir.appId]?.name);
}
if (errors.idsByErrorString.isNotEmpty) {
throw errors;
}
} finally {
@@ -677,7 +716,8 @@ class AppsProvider with ChangeNotifier {
Future<bool> installApk(
DownloadedApk file, BuildContext? firstTimeWithContext,
{bool needsBGWorkaround = false,
bool shizukuPretendToBeGooglePlay = false}) async {
bool shizukuPretendToBeGooglePlay = false,
List<DownloadedApk> additionalAPKs = const []}) async {
if (firstTimeWithContext != null &&
settingsProvider.beforeNewInstallsShareToAppVerifier &&
(await getInstalledInfo('dev.soupslurpr.appverifier')) != null) {
@@ -693,6 +733,7 @@ class AppsProvider with ChangeNotifier {
if (newInfo == null) {
try {
file.file.deleteSync(recursive: true);
additionalAPKs.forEach((a) => a.file.deleteSync(recursive: true));
} catch (e) {
//
} finally {
@@ -720,8 +761,10 @@ class AppsProvider with ChangeNotifier {
}
int? code;
if (!settingsProvider.useShizuku) {
code =
await AndroidPackageInstaller.installApk(apkFilePath: file.file.path);
var allAPKs = [file.file.path];
allAPKs.addAll(additionalAPKs.map((a) => a.file.path));
code = await AndroidPackageInstaller.installApk(
apkFilePath: allAPKs.join(','));
} else {
code = await ShizukuApkInstaller.installAPK(file.file.uri.toString(),
shizukuPretendToBeGooglePlay ? "com.android.vending" : "");
@@ -847,6 +890,11 @@ class AppsProvider with ChangeNotifier {
}
MapEntry<String, String>? apkUrl;
var trackOnly = apps[id]!.app.additionalSettings['trackOnly'] == true;
var refreshBeforeDownload =
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
if (refreshBeforeDownload) {
await checkUpdate(apps[id]!.app.id);
}
if (!trackOnly) {
// ignore: use_build_context_synchronously
apkUrl = await confirmAppFileUrl(apps[id]!.app, context, false);
@@ -1033,11 +1081,25 @@ class AppsProvider with ChangeNotifier {
throw ObtainiumError(tr('appNotFound'));
}
MapEntry<String, String>? fileUrl;
var refreshBeforeDownload =
apps[id]!.app.additionalSettings['refreshBeforeDownload'] == true;
if (refreshBeforeDownload) {
await checkUpdate(apps[id]!.app.id);
}
if (apps[id]!.app.apkUrls.isNotEmpty ||
apps[id]!.app.otherAssetUrls.isNotEmpty) {
// ignore: use_build_context_synchronously
fileUrl = await confirmAppFileUrl(apps[id]!.app, context, true,
MapEntry<String, String>? tempFileUrl = await confirmAppFileUrl(
apps[id]!.app, context, true,
evenIfSingleChoice: true);
if (tempFileUrl != null) {
fileUrl = MapEntry(
tempFileUrl.key,
await (SourceProvider().getSource(apps[id]!.app.url,
overrideSource: apps[id]!.app.overrideSource))
.apkUrlPrefetchModifier(tempFileUrl.value, apps[id]!.app.url,
apps[id]!.app.additionalSettings));
}
}
if (fileUrl != null) {
filesToDownload.add(MapEntry(fileUrl, apps[id]!.app));
@@ -1050,18 +1112,7 @@ class AppsProvider with ChangeNotifier {
Future<void> downloadFn(MapEntry<String, String> fileUrl, App app) async {
try {
var exportDir = await settingsProvider.getExportDir();
String downloadPath = '${await getStorageRootPath()}/Download';
bool downloadsAccessible = false;
try {
Directory(downloadPath).listSync();
downloadsAccessible = true;
} catch (e) {
//
}
if (!downloadsAccessible && exportDir != null) {
downloadPath = exportDir.path;
}
await downloadFile(fileUrl.value, fileUrl.key, true,
(double? progress) {
notificationsProvider
@@ -1110,17 +1161,25 @@ class AppsProvider with ChangeNotifier {
if (app?.app == null) {
return false;
}
var source = SourceProvider()
.getSource(app!.app.url, overrideSource: app.app.overrideSource);
var naiveStandardVersionDetection =
app!.app.additionalSettings['naiveStandardVersionDetection'] == true ||
SourceProvider()
.getSource(app.app.url, overrideSource: app.app.overrideSource)
.naiveStandardVersionDetection;
app.app.additionalSettings['naiveStandardVersionDetection'] == true ||
source.naiveStandardVersionDetection;
String? realInstalledVersion =
app.app.additionalSettings['useVersionCodeAsOSVersion'] == true
? app.installedInfo?.versionCode.toString()
: app.installedInfo?.versionName;
bool isHTMLWithNoVersionDetection =
(source.runtimeType == HTML().runtimeType &&
(app.app.additionalSettings['versionExtractionRegEx'] as String?)
?.isNotEmpty !=
true);
bool isDirectAPKLink = source.runtimeType == DirectAPKLink().runtimeType;
return app.app.additionalSettings['trackOnly'] != true &&
app.app.additionalSettings['releaseDateAsVersion'] != true &&
!isHTMLWithNoVersionDetection &&
!isDirectAPKLink &&
realInstalledVersion != null &&
app.app.installedVersion != null &&
(reconcileVersionDifferences(
@@ -1191,6 +1250,7 @@ class AppsProvider with ChangeNotifier {
!isVersionDetectionPossible(
AppInMemory(app, null, installedInfo, null))) {
app.additionalSettings['versionDetection'] = false;
app.installedVersion = app.latestVersion;
logs.add('Could not reconcile version formats for: ${app.id}');
modded = true;
}

View File

@@ -3,6 +3,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart';
class ObtainiumNotification {
@@ -44,23 +45,19 @@ class SilentUpdateNotification extends ObtainiumNotification {
SilentUpdateNotification(List<App> updates, bool succeeded, {int? id})
: super(
id ?? 3,
succeeded
? tr('appsUpdated')
: tr('appsNotUpdated'),
succeeded ? tr('appsUpdated') : tr('appsNotUpdated'),
'',
'APPS_UPDATED',
tr('appsUpdatedNotifChannel'),
tr('appsUpdatedNotifDescription'),
Importance.defaultImportance) {
message = updates.length == 1
? tr(succeeded
? 'xWasUpdatedToY'
: 'xWasNotUpdatedToY',
args: [updates[0].finalName, updates[0].latestVersion])
: plural(succeeded
? 'xAndNMoreUpdatesInstalled'
: "xAndNMoreUpdatesFailed",
updates.length - 1, args: [updates[0].finalName, (updates.length - 1).toString()]);
? tr(succeeded ? 'xWasUpdatedToY' : 'xWasNotUpdatedToY',
args: [updates[0].finalName, updates[0].latestVersion])
: plural(
succeeded ? 'xAndNMoreUpdatesInstalled' : "xAndNMoreUpdatesFailed",
updates.length - 1,
args: [updates[0].finalName, (updates.length - 1).toString()]);
}
}
@@ -214,7 +211,7 @@ class NotificationsProvider {
channelDescription: channelDescription,
importance: importance,
priority: importanceToPriority[importance]!,
groupKey: 'dev.imranr.obtainium.$channelCode',
groupKey: '$obtainiumId.$channelCode',
progress: progPercent ?? 0,
maxProgress: 100,
showProgress: progPercent != null,

View File

@@ -25,14 +25,12 @@ import 'package:obtainium/app_sources/jenkins.dart';
import 'package:obtainium/app_sources/neutroncode.dart';
import 'package:obtainium/app_sources/sourceforge.dart';
import 'package:obtainium/app_sources/sourcehut.dart';
import 'package:obtainium/app_sources/telegramapp.dart';
import 'package:obtainium/app_sources/tencent.dart';
import 'package:obtainium/app_sources/uptodown.dart';
import 'package:obtainium/app_sources/vlc.dart';
import 'package:obtainium/app_sources/whatsapp.dart';
import 'package:obtainium/components/generated_form.dart';
import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/mass_app_sources/githubstars.dart';
import 'package:obtainium/providers/logs_provider.dart';
import 'package:obtainium/providers/settings_provider.dart';
class AppNames {
@@ -153,10 +151,6 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
additionalSettings['autoApkFilterByArch'] = false;
}
if (source.runtimeType == HTML().runtimeType) {
// HTML 'fixed URL' support should be disabled if it previously did not exist
if (originalAdditionalSettings['supportFixedAPKURL'] == null) {
additionalSettings['supportFixedAPKURL'] = false;
}
// HTML key rename
if (originalAdditionalSettings['sortByFileNamesNotLinks'] != null) {
additionalSettings['sortByLastLinkSegment'] =
@@ -214,6 +208,72 @@ appJSONCompatibilityModifiers(Map<String, dynamic> json) {
'\\d+.\\d+.\\d+';
additionalSettings = replacementAdditionalSettings;
}
// WhatsApp from before it was removed should be converted to HTML (#1943)
if (json['url'] == 'https://whatsapp.com' &&
json['id'] == 'com.whatsapp' &&
json['author'] == 'Meta' &&
json['name'] == 'WhatsApp' &&
json['overrideSource'] == null &&
additionalSettings['trackOnly'] == false &&
additionalSettings['versionExtractionRegEx'] == '' &&
json['lastUpdateCheck'] != null) {
json['url'] = 'https://whatsapp.com/android';
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
HTML().combinedAppSpecificSettingFormItems);
replacementAdditionalSettings['refreshBeforeDownload'] = true;
additionalSettings = replacementAdditionalSettings;
}
// VLC from before it was removed should be converted to HTML (#1943)
if (json['url'] == 'https://videolan.org' &&
json['id'] == 'org.videolan.vlc' &&
json['author'] == 'VideoLAN' &&
json['name'] == 'VLC' &&
json['overrideSource'] == null &&
additionalSettings['trackOnly'] == false &&
additionalSettings['versionExtractionRegEx'] == '' &&
json['lastUpdateCheck'] != null) {
json['url'] = 'https://www.videolan.org/vlc/download-android.html';
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
HTML().combinedAppSpecificSettingFormItems);
replacementAdditionalSettings['refreshBeforeDownload'] = true;
replacementAdditionalSettings['intermediateLink'] =
<Map<String, dynamic>>[
{
'customLinkFilterRegex': 'APK',
'filterByLinkText': true,
'skipSort': false,
'reverseSort': false,
'sortByLastLinkSegment': false
},
{
'customLinkFilterRegex': 'arm64-v8a\\.apk\$',
'filterByLinkText': false,
'skipSort': false,
'reverseSort': false,
'sortByLastLinkSegment': false
}
];
replacementAdditionalSettings['versionExtractionRegEx'] =
'/vlc-android/([^/]+)/';
replacementAdditionalSettings['matchGroupToUse'] = "1";
additionalSettings = replacementAdditionalSettings;
}
// Telegram App from before it was removed should be converted to Direct APK Link (#1943)
if (json['url'] == 'https://telegram.org' &&
json['id'] == 'org.telegram.messenger.web' &&
json['author'] == 'Telegram' &&
json['name'] == 'Telegram' &&
json['overrideSource'] == null &&
additionalSettings['trackOnly'] == false &&
additionalSettings['versionExtractionRegEx'] == '' &&
json['lastUpdateCheck'] != null) {
json['url'] = 'https://telegram.org/dl/android/apk';
var newSource = DirectAPKLink();
json['overrideSource'] = newSource.runtimeType.toString();
var replacementAdditionalSettings = getDefaultValuesFromFormItems(
newSource.combinedAppSpecificSettingFormItems);
additionalSettings = replacementAdditionalSettings;
}
}
json['additionalSettings'] = jsonEncode(additionalSettings);
// F-Droid no longer needs cloudflare exception since override can be used - migrate apps appropriately
@@ -240,7 +300,7 @@ class App {
late String name;
String? installedVersion;
late String latestVersion;
List<MapEntry<String, String>> apkUrls = [];
List<MapEntry<String, String>> apkUrls = []; // Key is name, value is URL
List<MapEntry<String, String>> otherAssetUrls = [];
late int preferredApkIndex;
late Map<String, dynamic> additionalSettings;
@@ -304,7 +364,14 @@ class App {
otherAssetUrls: otherAssetUrls);
factory App.fromJson(Map<String, dynamic> json) {
json = appJSONCompatibilityModifiers(json);
Map<String, dynamic> originalJSON = new Map.from(json);
try {
json = appJSONCompatibilityModifiers(json);
} catch (e) {
json = originalJSON;
LogsProvider().add(
'Error running JSON compat modifiers: ${e.toString()}: ${originalJSON.toString()}');
}
return App(
json['id'] as String,
json['url'] as String,
@@ -586,6 +653,10 @@ abstract class AppSource {
label: tr('skipUpdateNotifications'))
],
[GeneratedFormTextField('about', label: tr('about'), required: false)],
[
GeneratedFormSwitch('refreshBeforeDownload',
label: tr('refreshBeforeDownload'))
]
];
// Previous 2 variables combined into one at runtime for convenient usage
@@ -808,9 +879,6 @@ class SourceProvider {
Tencent(),
Jenkins(),
APKMirror(),
VLC(),
WhatsApp(),
TelegramApp(),
NeutronCode(),
DirectAPKLink(),
HTML() // This should ALWAYS be the last option as they are tried in order

View File

@@ -14,7 +14,7 @@ packages:
description:
path: "."
ref: main
resolved-ref: ba2aa7a11edc2649d1d80c25ed9291521262f714
resolved-ref: bcad19e964d377da8816718032e5dbf6dd16ba3a
url: "https://github.com/ImranR98/android_package_installer"
source: git
version: "0.0.1"
@@ -231,10 +231,10 @@ packages:
dependency: "direct main"
description:
name: device_info_plus
sha256: c4af09051b4f0508f6c1dc0a5c085bf014d5c9a4a0678ce1799c2b4d716387a0
sha256: f545ffbadee826f26f2e1a0f0cbd667ae9a6011cc0f77c0f8f00a969655e6e95
url: "https://pub.dev"
source: hosted
version: "11.1.0"
version: "11.1.1"
device_info_plus_platform_interface:
dependency: transitive
description:
@@ -303,10 +303,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877
sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c"
url: "https://pub.dev"
source: hosted
version: "8.1.3"
version: "8.1.4"
fixnum:
dependency: transitive
description:
@@ -404,10 +404,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77"
sha256: "31cd0885738e87c72d6f055564d37fabcdacee743b396b78c7636c169cac64f5"
url: "https://pub.dev"
source: hosted
version: "0.14.1"
version: "0.14.2"
flutter_lints:
dependency: "direct dev"
description:
@@ -420,26 +420,26 @@ packages:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610
url: "https://pub.dev"
source: hosted
version: "17.2.4"
version: "18.0.1"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
version: "5.0.0"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52"
url: "https://pub.dev"
source: hosted
version: "7.2.0"
version: "8.0.0"
flutter_localizations:
dependency: transitive
description: flutter
@@ -449,10 +449,10 @@ packages:
dependency: "direct main"
description:
name: flutter_markdown
sha256: f0e599ba89c9946c8e051780f0ec99aba4ba15895e0380a7ab68f420046fc44e
sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e"
url: "https://pub.dev"
source: hosted
version: "0.7.4+1"
version: "0.7.4+3"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@@ -667,18 +667,18 @@ packages:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.14"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@@ -731,10 +731,10 @@ packages:
dependency: transitive
description:
name: permission_handler_html
sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
url: "https://pub.dev"
source: hosted
version: "0.1.3+2"
version: "0.1.3+5"
permission_handler_platform_interface:
dependency: transitive
description:
@@ -819,10 +819,10 @@ packages:
dependency: "direct main"
description:
name: share_plus
sha256: "3af2cda1752e5c24f2fc04b6083b40f013ffe84fb90472f30c6499a9213d5442"
sha256: "9c9bafd4060728d7cdb2464c341743adbd79d327cb067ec7afb64583540b47c8"
url: "https://pub.dev"
source: hosted
version: "10.1.1"
version: "10.1.2"
share_plus_platform_interface:
dependency: transitive
description:
@@ -835,18 +835,18 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.3.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549"
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.3.4"
shared_preferences_foundation:
dependency: transitive
description:
@@ -929,10 +929,10 @@ packages:
dependency: "direct main"
description:
name: sqflite
sha256: "79a297dc3cc137e758c6a4baf83342b039e5a6d2436fcdf3f96a00adaaf2ad62"
sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
sqflite_android:
dependency: transitive
description:
@@ -945,18 +945,18 @@ packages:
dependency: transitive
description:
name: sqflite_common
sha256: "4468b24876d673418a7b7147e5a08a715b4998a7ae69227acafaab762e0e5490"
sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709"
url: "https://pub.dev"
source: hosted
version: "2.5.4+5"
version: "2.5.4+6"
sqflite_darwin:
dependency: transitive
description:
name: sqflite_darwin
sha256: "769733dddf94622d5541c73e4ddc6aa7b252d865285914b6fcd54a63c4b4f027"
sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474"
url: "https://pub.dev"
source: hosted
version: "2.4.1-1"
version: "2.4.1"
sqflite_platform_interface:
dependency: transitive
description:
@@ -1017,10 +1017,10 @@ packages:
dependency: transitive
description:
name: timezone
sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
sha256: ffc9d5f4d1193534ef051f9254063fa53d588609418c84299956c3db9383587d
url: "https://pub.dev"
source: hosted
version: "0.9.4"
version: "0.10.0"
typed_data:
dependency: transitive
description:
@@ -1057,26 +1057,26 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626"
url: "https://pub.dev"
source: hosted
version: "6.3.1"
version: "6.3.2"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "3.2.1"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
url_launcher_platform_interface:
dependency: transitive
description:
@@ -1145,10 +1145,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
sha256: "74693a212d990b32e0b7055d27db973a18abf31c53942063948cdfaaef9787ba"
sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
version: "4.1.0"
webview_flutter_platform_interface:
dependency: transitive
description:
@@ -1161,18 +1161,18 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: d4034901d96357beb1b6717ebf7d583c88e40cfc6eb85fe76dd1bf0979a9f251
sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb
url: "https://pub.dev"
source: hosted
version: "3.16.0"
version: "3.16.3"
win32:
dependency: transitive
description:
name: win32
sha256: "10169d3934549017f0ae278ccb07f828f9d6ea21573bab0fb77b0e1ef0fce454"
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
url: "https://pub.dev"
source: hosted
version: "5.7.2"
version: "5.9.0"
win32_registry:
dependency: transitive
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
# 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.
version: 1.1.29+2286
version: 1.1.36+2293
environment:
sdk: '>=3.0.0 <4.0.0'
@@ -38,7 +38,7 @@ dependencies:
cupertino_icons: ^1.0.5
path_provider: ^2.0.11
flutter_fgbg: ^0.6.0
flutter_local_notifications: ^17.0.0
flutter_local_notifications: ^18.0.0
provider: ^6.0.3
http: ^1.0.0
webview_flutter: ^4.0.0