-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Periodically check for updates and alert user (#236)
Users can inadvertently get stuck on older versions of the app; e.g., by installing from one F-Droid repository that stops hosting the app at some later time. Analytics from the Play Store also shows a long tail of users who are, for some reason, on an older version. On resuming `MainActivity`, and approximately once per day, check and see if a newer version of Pachli is available, and prompt the user to update by going to the relevant install location (Google Play, F-Droid, or GitHub). The dialog prompt allows them to ignore this specific version, or disable all future update notifications. This is also exposed through the preferences, so the user can adjust it there too. A different update check method is used for each installation location. - F-Droid: Use the F-Droid API to query for the newest released version - GitHub: Use the GitHub API to query for the newest release, and check the APK filename attached to that release - Google Play: Use the Play in-app-updates library (https://developer.android.com/guide/playcore/in-app-updates) to query for the newest released version These are kept in different build flavours (source sets), so that e.g., the build for the F-Droid store can only query the F-Droid API, the UI strings are specific to F-Droid, etc. This also ensures that the update service libraries are specific to that build and do not "cross-contaminate". Note that this *does not* update the app, it takes the user to either the relevant store page (F-Droid, Play) or GitHub release page. The user must still start the update from that page. CI configuration is updated to build the different flavours.
- Loading branch information
1 parent
86dee94
commit dda9dde
Showing
25 changed files
with
675 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,17 +27,17 @@ jobs: | |
with: | ||
cache-read-only: ${{ github.ref != 'refs/heads/main' }} | ||
|
||
- name: Build APK | ||
run: ./gradlew assembleBlueRelease --stacktrace | ||
- name: Build GitHub APK | ||
run: ./gradlew assembleBlueGithubRelease --stacktrace | ||
|
||
- name: Build AAB | ||
run: ./gradlew :app:bundleBlueRelease --stacktrace | ||
- name: Build Google AAB | ||
run: ./gradlew :app:bundleBlueGoogleRelease --stacktrace | ||
|
||
- uses: r0adkll/[email protected] | ||
name: Sign app APK | ||
name: Sign GitHub APK | ||
id: sign_app_apk | ||
with: | ||
releaseDirectory: app/build/outputs/apk/blue/release | ||
releaseDirectory: app/build/outputs/apk/blueGithub/release | ||
signingKeyBase64: ${{ secrets.SIGNING_KEY }} | ||
alias: ${{ secrets.SIGNING_KEY_ALIAS }} | ||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} | ||
|
@@ -46,10 +46,10 @@ jobs: | |
BUILD_TOOLS_VERSION: "34.0.0" | ||
|
||
- uses: r0adkll/[email protected] | ||
name: Sign app AAB | ||
name: Sign Google AAB | ||
id: sign_app_aab | ||
with: | ||
releaseDirectory: app/build/outputs/bundle/blueRelease | ||
releaseDirectory: app/build/outputs/bundle/blueGoogleRelease | ||
signingKeyBase64: ${{ secrets.SIGNING_KEY }} | ||
alias: ${{ secrets.SIGNING_KEY_ALIAS }} | ||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} | ||
|
@@ -80,4 +80,4 @@ jobs: | |
track: internal | ||
whatsNewDirectory: googleplay/whatsnew | ||
status: completed | ||
mappingFile: app/build/outputs/mapping/blueRelease/mapping.txt | ||
mappingFile: app/build/outputs/mapping/blueGoogleRelease/mapping.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,19 +30,19 @@ jobs: | |
cache-read-only: ${{ github.ref != 'refs/heads/main' }} | ||
|
||
- name: Test | ||
run: ./gradlew app:testOrangeReleaseUnitTest --stacktrace | ||
run: ./gradlew app:testOrangeGoogleReleaseUnitTest --stacktrace | ||
|
||
- name: Build APK | ||
run: ./gradlew assembleOrangeRelease --stacktrace | ||
run: ./gradlew assembleOrangeGoogleRelease --stacktrace | ||
|
||
- name: Build AAB | ||
run: ./gradlew :app:bundleOrangeRelease --stacktrace | ||
run: ./gradlew :app:bundleOrangeGoogleRelease --stacktrace | ||
|
||
- uses: r0adkll/[email protected] | ||
name: Sign app APK | ||
id: sign_app_apk | ||
with: | ||
releaseDirectory: app/build/outputs/apk/orange/release | ||
releaseDirectory: app/build/outputs/apk/orangeGoogle/release | ||
signingKeyBase64: ${{ secrets.SIGNING_KEY }} | ||
alias: ${{ secrets.SIGNING_KEY_ALIAS }} | ||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} | ||
|
@@ -54,7 +54,7 @@ jobs: | |
name: Sign app AAB | ||
id: sign_app_aab | ||
with: | ||
releaseDirectory: app/build/outputs/bundle/orangeRelease | ||
releaseDirectory: app/build/outputs/bundle/orangeGoogleRelease | ||
signingKeyBase64: ${{ secrets.SIGNING_KEY }} | ||
alias: ${{ secrets.SIGNING_KEY_ALIAS }} | ||
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }} | ||
|
@@ -85,4 +85,4 @@ jobs: | |
track: production | ||
whatsNewDirectory: googleplay/whatsnew | ||
status: completed | ||
mappingFile: app/build/outputs/mapping/orangeRelease/mapping.txt | ||
mappingFile: app/build/outputs/mapping/orangeGoogleRelease/mapping.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2023 Pachli Association | ||
* | ||
* This file is a part of Pachli. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under the terms of the | ||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with Pachli; if not, | ||
* see <http://www.gnu.org/licenses>. | ||
*/ | ||
|
||
package app.pachli.di | ||
|
||
import app.pachli.updatecheck.FdroidService | ||
import at.connyduck.calladapter.networkresult.NetworkResultCallAdapterFactory | ||
import com.google.gson.Gson | ||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.components.SingletonComponent | ||
import okhttp3.OkHttpClient | ||
import retrofit2.Retrofit | ||
import retrofit2.converter.gson.GsonConverterFactory | ||
import retrofit2.create | ||
import javax.inject.Singleton | ||
|
||
@InstallIn(SingletonComponent::class) | ||
@Module | ||
object UpdateCheckModule { | ||
@Provides | ||
@Singleton | ||
fun providesFdroidService( | ||
httpClient: OkHttpClient, | ||
gson: Gson | ||
): FdroidService = Retrofit.Builder() | ||
.baseUrl("https://f-droid.org") | ||
.client(httpClient) | ||
.addConverterFactory(GsonConverterFactory.create(gson)) | ||
.addCallAdapterFactory(NetworkResultCallAdapterFactory.create()) | ||
.build() | ||
.create() | ||
} |
40 changes: 40 additions & 0 deletions
40
app/src/fdroid/kotlin/app/pachli/updatecheck/FdroidService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* | ||
* Copyright 2023 Pachli Association | ||
* | ||
* This file is a part of Pachli. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under the terms of the | ||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with Pachli; if not, | ||
* see <http://www.gnu.org/licenses>. | ||
*/ | ||
|
||
package app.pachli.updatecheck | ||
|
||
import at.connyduck.calladapter.networkresult.NetworkResult | ||
import retrofit2.http.GET | ||
import retrofit2.http.Path | ||
|
||
data class FdroidPackageVersion( | ||
val versionName: String, | ||
val versionCode: Int | ||
) | ||
|
||
data class FdroidPackage( | ||
val packageName: String, | ||
val suggestedVersionCode: Int, | ||
val packages: List<FdroidPackageVersion> | ||
) | ||
|
||
interface FdroidService { | ||
@GET("/api/v1/packages/{package}") | ||
suspend fun getPackage( | ||
@Path("package") pkg: String | ||
): NetworkResult<FdroidPackage> | ||
} |
39 changes: 39 additions & 0 deletions
39
app/src/fdroid/kotlin/app/pachli/updatecheck/UpdateCheck.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* Copyright 2023 Pachli Association | ||
* | ||
* This file is a part of Pachli. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under the terms of the | ||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with Pachli; if not, | ||
* see <http://www.gnu.org/licenses>. | ||
*/ | ||
|
||
package app.pachli.updatecheck | ||
|
||
import android.content.Intent | ||
import android.net.Uri | ||
import app.pachli.BuildConfig | ||
import app.pachli.util.SharedPreferencesRepository | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
class UpdateCheck @Inject constructor( | ||
sharedPreferencesRepository: SharedPreferencesRepository, | ||
private val fdroidService: FdroidService | ||
) : UpdateCheckBase(sharedPreferencesRepository) { | ||
override val updateIntent = Intent(Intent.ACTION_VIEW).apply { | ||
data = Uri.parse("market://details?id=${BuildConfig.APPLICATION_ID}") | ||
} | ||
|
||
override suspend fun remoteFetchLatestVersionCode(): Int? { | ||
return fdroidService.getPackage(BuildConfig.APPLICATION_ID).getOrNull()?.suggestedVersionCode | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?xml version="1.0" encoding="utf-8"?><!-- | ||
~ Copyright 2023 Pachli Association | ||
~ | ||
~ This file is a part of Pachli. | ||
~ | ||
~ This program is free software; you can redistribute it and/or modify it under the terms of the | ||
~ GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||
~ License, or (at your option) any later version. | ||
~ | ||
~ Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||
~ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
~ Public License for more details. | ||
~ | ||
~ You should have received a copy of the GNU General Public License along with Pachli; if not, | ||
~ see <http://www.gnu.org/licenses>. | ||
--> | ||
|
||
<resources> | ||
<string name="update_dialog_message">Open F-Droid to see the details?</string> | ||
<string name="update_dialog_positive">Open F-Droid</string> | ||
</resources> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2023 Pachli Association | ||
* | ||
* This file is a part of Pachli. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it under the terms of the | ||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even | ||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License along with Pachli; if not, | ||
* see <http://www.gnu.org/licenses>. | ||
*/ | ||
|
||
package app.pachli.di | ||
|
||
import app.pachli.updatecheck.GitHubService | ||
import at.connyduck.calladapter.networkresult.NetworkResultCallAdapterFactory | ||
import com.google.gson.Gson | ||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.components.SingletonComponent | ||
import okhttp3.OkHttpClient | ||
import retrofit2.Retrofit | ||
import retrofit2.converter.gson.GsonConverterFactory | ||
import retrofit2.create | ||
import javax.inject.Singleton | ||
|
||
@InstallIn(SingletonComponent::class) | ||
@Module | ||
object UpdateCheckModule { | ||
@Provides | ||
@Singleton | ||
fun providesGitHubService( | ||
httpClient: OkHttpClient, | ||
gson: Gson | ||
): GitHubService = Retrofit.Builder() | ||
.baseUrl("https://api.github.com") | ||
.client(httpClient) | ||
.addConverterFactory(GsonConverterFactory.create(gson)) | ||
.addCallAdapterFactory(NetworkResultCallAdapterFactory.create()) | ||
.build() | ||
.create() | ||
} |
Oops, something went wrong.