From 05d91f71eaa6d3f36186bcedee2d8c9ff7c0df43 Mon Sep 17 00:00:00 2001 From: Catfriend1 <16361913+Catfriend1@users.noreply.github.com> Date: Sun, 27 Oct 2024 19:44:30 +0100 Subject: [PATCH] Create signed GitHub and play releases (#1161) Improve Android 15 compatibility according to play policies. --- App_build_and_release.cmd | 28 ++++----- app/build.gradle.kts | 3 + app/postbuild.py | 61 +++---------------- .../service/FlavorConstants.java | 9 +++ app/src/gplay/AndroidManifest.xml | 19 ++++++ .../service/FlavorConstants.java | 9 +++ .../fragments/DrawerFragment.java | 2 +- .../syncthingandroid/service/Constants.java | 5 ++ .../service/NotificationHandler.java | 4 +- .../service/ReceiverManager.java | 8 ++- app/src/main/res/values-pt/strings.xml | 2 +- app/src/release/AndroidManifest.xml | 7 --- .../service/FlavorConstants.java | 9 +++ git-log.cmd | 3 + postbuild_copy_apk.cmd | 8 +-- 15 files changed, 90 insertions(+), 87 deletions(-) create mode 100644 app/src/debug/java/com/nutomic/syncthingandroid/service/FlavorConstants.java create mode 100644 app/src/gplay/AndroidManifest.xml create mode 100644 app/src/gplay/java/com/nutomic/syncthingandroid/service/FlavorConstants.java delete mode 100644 app/src/release/AndroidManifest.xml create mode 100644 app/src/release/java/com/nutomic/syncthingandroid/service/FlavorConstants.java create mode 100644 git-log.cmd diff --git a/App_build_and_release.cmd b/App_build_and_release.cmd index ea18571c2..74d5fbc33 100644 --- a/App_build_and_release.cmd +++ b/App_build_and_release.cmd @@ -6,17 +6,16 @@ cls REM REM Script Consts. SET CLEANUP_BEFORE_BUILD=1 -SET SKIP_RELEASE_BUILD=1 REM REM Runtime Variables. IF EXIST "%LocalAppData%\Android\Sdk" SET "ANDROID_SDK_ROOT=%LocalAppData%\Android\Sdk" IF NOT DEFINED ANDROID_SDK_ROOT SET "ANDROID_SDK_ROOT=%SCRIPT_PATH%..\syncthing-android-prereq" -IF NOT DEFINED ANDROID_PUBLISHER_CREDENTIALS echo [WARN] ANDROID_PUBLISHER_CREDENTIALS env var not set. We will skip the signed release build. & SET SKIP_RELEASE_BUILD=1 REM REM SET ANDROID_PUBLISHER_CREDENTIALS=%userprofile%\.android\play_key.json" REM SET SYNCTHING_RELEASE_STORE_FILE="%userprofile%\.android\signing_key.jks" SET SYNCTHING_RELEASE_KEY_ALIAS=Syncthing-Fork -SET BUILD_FLAVOUR_GPLAY=release +SET BUILD_FLAVOUR_RELEASE=release +SET BUILD_FLAVOUR_GPLAY=gplay title %SYNCTHING_RELEASE_KEY_ALIAS% - Build APK REM SET GIT_INSTALL_DIR=%ProgramFiles%\Git @@ -37,9 +36,6 @@ SET LIBCOUNT= for /f "tokens=*" %%A IN ('dir /s /a "%SCRIPT_PATH%app\src\main\jniLibs\*" 2^>NUL: ^| find /C "libsyncthingnative.so"') DO SET LIBCOUNT=%%A IF NOT "%LIBCOUNT%" == "4" echo [ERROR] SyncthingNative[s] "libsyncthingnative.so" are missing. Please run "gradlew buildNative" first. & goto :eos REM -REM Check if we should skip the release build and just make a debug build. -IF "%SKIP_RELEASE_BUILD%" == "1" goto :absLint -REM echo [INFO] Let's prepare a new "%SYNCTHING_RELEASE_KEY_ALIAS%" release. REM echo [INFO] Checking release prerequisites ... @@ -47,7 +43,7 @@ IF NOT EXIST "%ANDROID_PUBLISHER_CREDENTIALS%" echo [ERROR] ANDROID_PUBLISHER_CR FOR /F "tokens=*" %%i in ('type "%ANDROID_PUBLISHER_CREDENTIALS%" 2^>NUL:') DO SET ANDROID_PUBLISHER_CREDENTIALS=%%i REM REM User has to enter the signing password if it is not filled in here. -SET SIGNING_PASSWORD= +REM SET SIGNING_PASSWORD= IF DEFINED SIGNING_PASSWORD goto :absLint :enterSigningPassword setlocal DisableDelayedExpansion @@ -63,15 +59,16 @@ REM copy /y "%SCRIPT_PATH%app\src\main\play\release-notes\en-GB\beta.txt" "%SCRIPT_PATH%app\src\main\play\release-notes\en-GB\default.txt" REM echo [INFO] Running lint before building ... -IF "%SKIP_RELEASE_BUILD%" == "1" call gradlew --quiet lintDebug & SET RESULT=%ERRORLEVEL% -IF NOT "%SKIP_RELEASE_BUILD%" == "1" call gradlew --quiet lint & SET RESULT=%ERRORLEVEL% -IF NOT "!RESULT!" == "0" echo [ERROR] "gradlew lint" exited with code #%RESULT%. & goto :eos REM -call :buildApk debug +call gradlew --quiet lint%BUILD_FLAVOUR_RELEASE% & SET RESULT=%ERRORLEVEL% +IF NOT "!RESULT!" == "0" echo [ERROR] "gradlew lint%BUILD_FLAVOUR_RELEASE%" exited with code #%RESULT%. & goto :eos +REM +call gradlew --quiet lint%BUILD_FLAVOUR_GPLAY% & SET RESULT=%ERRORLEVEL% +IF NOT "!RESULT!" == "0" echo [ERROR] "gradlew lint%BUILD_FLAVOUR_GPLAY%" exited with code #%RESULT%. & goto :eos REM -REM Check if we should skip the release build and just make a debug build. -IF "%SKIP_RELEASE_BUILD%" == "1" goto :absPostBuildScript +REM Building APK REM +call :buildApk %BUILD_FLAVOUR_RELEASE% call :buildApk %BUILD_FLAVOUR_GPLAY% REM IF "%CLEANUP_BEFORE_BUILD%" == "1" del /f "%SCRIPT_PATH%app\build\outputs\bundle\%BUILD_FLAVOUR_GPLAY%\app-%BUILD_FLAVOUR_GPLAY%.aab" 2> NUL: @@ -93,9 +90,6 @@ REM REM Copy build artifacts with correct file name to upload folder. call "%SCRIPT_PATH%postbuild_copy_apk.cmd" REM -REM Check if we should skip the release upload and finish here. -IF "%SKIP_RELEASE_BUILD%" == "1" goto :eos -REM :askUserReadyToPublish SET UI_ANSWER= SET /p UI_ANSWER=Are you ready to publish this release to GPlay? [y/n] @@ -144,6 +138,6 @@ echo [INFO] Building Android APK variant "%BA_BUILD_TYPE%" ... call gradlew --quiet assemble%BA_BUILD_TYPE% SET RESULT=%ERRORLEVEL% IF NOT "%RESULT%" == "0" echo [ERROR] "gradlew assemble%BA_BUILD_TYPE%" exited with code #%RESULT%. & goto :eos -type "app\build\intermediates\merged_manifests\%BA_BUILD_TYPE%\AndroidManifest.xml" | findstr /i "android:version" +type "app\build\intermediates\merged_manifests\%BA_BUILD_TYPE%\process%BA_BUILD_TYPE%Manifest\AndroidManifest.xml" | findstr /i "android:version" REM goto :eof diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 50295b241..0eeb5e5b8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -82,6 +82,9 @@ android { .getOrNull() .takeIf { it?.storeFile != null } } + create("gplay") { + initWith(getByName("release")) + } } compileOptions { diff --git a/app/postbuild.py b/app/postbuild.py index cd0112ba5..8eb06253b 100644 --- a/app/postbuild.py +++ b/app/postbuild.py @@ -11,6 +11,9 @@ # - Python 2.7.15 # - Python 3.7.0 # +# Command line: +# gradlew postbuildscript +# SUPPORTED_PYTHON_PLATFORMS = ['Windows', 'Linux', 'Darwin'] @@ -76,46 +79,6 @@ def calcAndPrintCertHash(apk_fullfn, apk_build_type): return None -def pushAPKtoDevice(apk_package_name, apk_fullfn_to_push): - if not debug_apk or not os.path.isfile(debug_apk): - print('[ERROR] pushAPKtoDevice: APK not found.'); - return None - - # Check if adb is available. - adb_bin = which("adb"); - if not adb_bin: - print('[WARNING] adb is not available on the PATH.') - # install_adb(); - # Retry: Check if adb is available. - # adb_bin = which("adb"); - if not adb_bin: - print('[ERROR] adb is not available on the PATH.') - sys.exit(0) - print('[INFO] adb_bin=\'' + adb_bin + '\'') - - print('[INFO] Connecting to attached usb device ...') - try: - subprocess.check_call([ - adb_bin, - 'devices' - ]) - except: - sys.exit(0) - - print('[INFO] Installing APK to attached usb device ...') - try: - subprocess.check_call(adb_bin + ' install -r --user 0 ' + apk_fullfn_to_push) - except: - sys.exit(0) - - print('[INFO] Starting app ...') - try: - subprocess.check_call(adb_bin + ' shell monkey -p ' + apk_package_name + ' 1') - except: - sys.exit(0) - - return None - ################# # Script Main # @@ -127,22 +90,12 @@ def pushAPKtoDevice(apk_package_name, apk_fullfn_to_push): # Build FullFNs. current_dir = os.path.dirname(os.path.realpath(__file__)) -enable_push_to_device = os.path.realpath(os.path.join(current_dir, "..", "#enable_push_to_device")) -debug_apk = os.path.realpath(os.path.join(current_dir, 'build', 'outputs', 'apk', 'debug', 'app-debug.apk')) +# debug_apk = os.path.realpath(os.path.join(current_dir, 'build', 'outputs', 'apk', 'debug', 'app-debug.apk')) +gplay_apk = os.path.realpath(os.path.join(current_dir, 'build', 'outputs', 'apk', 'gplay', 'app-gplay.apk')) release_apk = os.path.realpath(os.path.join(current_dir, 'build', 'outputs', 'apk', 'release', 'app-release.apk')) # Calculate certificate hash of built APKs and output if it matches a known release channel. # See the wiki for more details: wiki/Switch-between-releases_Verify-APK-is-genuine.md -calcAndPrintCertHash(debug_apk, "debug"); +# calcAndPrintCertHash(debug_apk, "debug"); +calcAndPrintCertHash(gplay_apk, "gplay"); calcAndPrintCertHash(release_apk, "release"); - -# -# Check if push to device is enabled. -# -# Purpose: Push to device eases deployment on a real Android test device for developers -# that cannot or do not wish to install the full Android Studio IDE. -if not enable_push_to_device or not os.path.isfile(enable_push_to_device): - # print('[INFO] push-to-device after build is DISABLED. To enable it, run \'echo . > ' + enable_push_to_device + '\'') - sys.exit(0) - -pushAPKtoDevice("com.github.catfriend1.syncthingandroid.debug", debug_apk) diff --git a/app/src/debug/java/com/nutomic/syncthingandroid/service/FlavorConstants.java b/app/src/debug/java/com/nutomic/syncthingandroid/service/FlavorConstants.java new file mode 100644 index 000000000..e2a28ab5b --- /dev/null +++ b/app/src/debug/java/com/nutomic/syncthingandroid/service/FlavorConstants.java @@ -0,0 +1,9 @@ +package com.nutomic.syncthingandroid.service; + +import android.content.pm.ServiceInfo; + +public class FlavorConstants { + + public static final Integer FOREGROUND_SERVICE_TYPE = ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + +} diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml new file mode 100644 index 000000000..be1cce4fc --- /dev/null +++ b/app/src/gplay/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/app/src/gplay/java/com/nutomic/syncthingandroid/service/FlavorConstants.java b/app/src/gplay/java/com/nutomic/syncthingandroid/service/FlavorConstants.java new file mode 100644 index 000000000..f0552e974 --- /dev/null +++ b/app/src/gplay/java/com/nutomic/syncthingandroid/service/FlavorConstants.java @@ -0,0 +1,9 @@ +package com.nutomic.syncthingandroid.service; + +import android.content.pm.ServiceInfo; + +public class FlavorConstants { + + public static final Integer FOREGROUND_SERVICE_TYPE = ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC; + +} diff --git a/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java b/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java index c21180cc0..79c397dee 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/fragments/DrawerFragment.java @@ -134,7 +134,7 @@ private void updateUI() { * Reason: SyncthingNative's Web UI is not approved by Google because * it is lacking full DPAD navigation support. See issue #567. */ - mDrawerActionWebGui.setVisibility((!mRunningOnTV) ? View.VISIBLE : View.GONE); + mDrawerActionWebGui.setVisibility((!mRunningOnTV || Constants.isDebuggable(getContext())) ? View.VISIBLE : View.GONE); // Enable buttons if syncthing is running. mDrawerRecentChanges.setEnabled(syncthingRunning); diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java index 943ab9ade..26a13cabc 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/Constants.java @@ -1,6 +1,7 @@ package com.nutomic.syncthingandroid.service; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.os.Build; import android.text.TextUtils; @@ -276,6 +277,10 @@ public static Boolean isRunningOnEmulator() { ); } + public static Boolean isDebuggable(Context context) { + return (0 != (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE)); + } + /** * Decide if we should enforce HTTPS when accessing the Web UI and REST API. * Android 4.4 and earlier don't have support for TLS 1.2 requiring us to diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java b/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java index 8743e1c71..a4915fca2 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/NotificationHandler.java @@ -212,8 +212,8 @@ public void updatePersistentNotification(SyncthingService service, if (!appShutdownInProgress) { if (startForegroundService) { Log.v(TAG, "Starting foreground service or updating notification"); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - service.startForeground(idToShow, builder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + service.startForeground(idToShow, builder.build(), FlavorConstants.FOREGROUND_SERVICE_TYPE); } else { service.startForeground(idToShow, builder.build()); } diff --git a/app/src/main/java/com/nutomic/syncthingandroid/service/ReceiverManager.java b/app/src/main/java/com/nutomic/syncthingandroid/service/ReceiverManager.java index 8168c29e8..b517dd90d 100644 --- a/app/src/main/java/com/nutomic/syncthingandroid/service/ReceiverManager.java +++ b/app/src/main/java/com/nutomic/syncthingandroid/service/ReceiverManager.java @@ -3,6 +3,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.IntentFilter; +import android.os.Build; import android.util.Log; import java.util.ArrayList; @@ -17,9 +18,14 @@ public class ReceiverManager { private static List mReceivers = new ArrayList(); + @SuppressWarnings("UnspecifiedRegisterReceiverFlag") public static synchronized void registerReceiver(Context context, BroadcastReceiver receiver, IntentFilter intentFilter) { mReceivers.add(receiver); - context.registerReceiver(receiver, intentFilter); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.registerReceiver(receiver, intentFilter, Context.RECEIVER_EXPORTED); + } else { + context.registerReceiver(receiver, intentFilter); + } LogV("Registered receiver: " + receiver + " with filter: " + intentFilter); } diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 7f411191c..5ac4bedf3 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -517,4 +517,4 @@ Escolha um tipo de versionamento para habilitá-lo. Tipo: Simples Tipo: Lixo - \ No newline at end of file + diff --git a/app/src/release/AndroidManifest.xml b/app/src/release/AndroidManifest.xml deleted file mode 100644 index 8a762a288..000000000 --- a/app/src/release/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/app/src/release/java/com/nutomic/syncthingandroid/service/FlavorConstants.java b/app/src/release/java/com/nutomic/syncthingandroid/service/FlavorConstants.java new file mode 100644 index 000000000..e2a28ab5b --- /dev/null +++ b/app/src/release/java/com/nutomic/syncthingandroid/service/FlavorConstants.java @@ -0,0 +1,9 @@ +package com.nutomic.syncthingandroid.service; + +import android.content.pm.ServiceInfo; + +public class FlavorConstants { + + public static final Integer FOREGROUND_SERVICE_TYPE = ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + +} diff --git a/git-log.cmd b/git-log.cmd new file mode 100644 index 000000000..4b9823eb6 --- /dev/null +++ b/git-log.cmd @@ -0,0 +1,3 @@ +@echo off +git log > "X:\git.log" +start "" "X:\git.log" diff --git a/postbuild_copy_apk.cmd b/postbuild_copy_apk.cmd index 9ea866d95..5060fc8ae 100644 --- a/postbuild_copy_apk.cmd +++ b/postbuild_copy_apk.cmd @@ -67,8 +67,8 @@ echo [INFO] VERSION_NAME=[%VERSION_NAME%], commit=[%COMMIT_SHORT_HASH%]=[%COMMIT echo [INFO] Copying APK to same directory ... REM REM Copy APK to be ready for upload to the GitHub release page. -SET APK_GITHUB_NEW_FILENAME=%APPLICATION_ID%_github_v%VERSION_NAME%_%COMMIT_SHORT_HASH%.apk -call :copyIfExist %SCRIPT_PATH%app\build\outputs\apk\debug\app-debug.apk %SCRIPT_PATH%app\build\outputs\apk\debug\%APK_GITHUB_NEW_FILENAME% +SET APK_RELEASE_NEW_FILENAME=%APPLICATION_ID%_github_v%VERSION_NAME%_%COMMIT_SHORT_HASH%.apk +call :copyIfExist %SCRIPT_PATH%app\build\outputs\apk\release\app-release.apk %SCRIPT_PATH%app\build\outputs\apk\release\%APK_RELEASE_NEW_FILENAME% REM SET APK_GPLAY_NEW_FILENAME=%APPLICATION_ID%_gplay_v%VERSION_NAME%_%COMMIT_SHORT_HASH%.apk IF NOT "%SKIP_RELEASE_BUILD%" == "1" call :copyIfExist %SCRIPT_PATH%app\build\outputs\apk\%BUILD_FLAVOUR_GPLAY%\app-%BUILD_FLAVOUR_GPLAY%.apk %SCRIPT_PATH%app\build\outputs\apk\%BUILD_FLAVOUR_GPLAY%\%APK_GPLAY_NEW_FILENAME% @@ -76,7 +76,7 @@ REM REM Copy both APK to temporary storage location if the storage is available. IF EXIST %TEMP_OUTPUT_FOLDER%\ ( echo [INFO] Copying APK to [%TEMP_OUTPUT_FOLDER%] ... - copy /y %SCRIPT_PATH%app\build\outputs\apk\debug\%APK_GITHUB_NEW_FILENAME% %TEMP_OUTPUT_FOLDER%\ 2> NUL: + copy /y %SCRIPT_PATH%app\build\outputs\apk\release\%APK_RELEASE_NEW_FILENAME% %TEMP_OUTPUT_FOLDER%\ 2> NUL: IF NOT "%SKIP_RELEASE_BUILD%" == "1" copy /y %SCRIPT_PATH%app\build\outputs\apk\%BUILD_FLAVOUR_GPLAY%\%APK_GPLAY_NEW_FILENAME% %TEMP_OUTPUT_FOLDER%\ 2> NUL: ) REM @@ -137,7 +137,7 @@ IF %FILE_SIZE% LSS 23 echo [ERROR] Download source code FAILED #3. & DEL /F %TMP REM REM Package built APKs into ZIP. echo [INFO] Adding built APKs to source code ZIP ... -%TMP_DSC_SEVENZIP_EXE% -y -bso0 a %TMP_DSC_ZIPFILE_FULLFN% %TEMP_OUTPUT_FOLDER%\%APK_GITHUB_NEW_FILENAME% +%TMP_DSC_SEVENZIP_EXE% -y -bso0 a %TMP_DSC_ZIPFILE_FULLFN% %TEMP_OUTPUT_FOLDER%\%APK_RELEASE_NEW_FILENAME% IF NOT "%SKIP_RELEASE_BUILD%" == "1" %TMP_DSC_SEVENZIP_EXE% -y -bso0 a %TMP_DSC_ZIPFILE_FULLFN% %TEMP_OUTPUT_FOLDER%\%APK_GPLAY_NEW_FILENAME% REM goto :eof