Skip to content

Commit

Permalink
Create signed GitHub and play releases (#1161)
Browse files Browse the repository at this point in the history
Improve Android 15 compatibility according to play policies.
  • Loading branch information
Catfriend1 authored Oct 27, 2024
1 parent 21e4a23 commit 05d91f7
Show file tree
Hide file tree
Showing 15 changed files with 90 additions and 87 deletions.
28 changes: 11 additions & 17 deletions App_build_and_release.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -37,17 +36,14 @@ 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 ...
IF NOT EXIST "%ANDROID_PUBLISHER_CREDENTIALS%" echo [ERROR] ANDROID_PUBLISHER_CREDENTIALS file not found. Please retry. & pause & goto :checkPrerequisites
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
Expand All @@ -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:
Expand All @@ -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]
Expand Down Expand Up @@ -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
3 changes: 3 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ android {
.getOrNull()
.takeIf { it?.storeFile != null }
}
create("gplay") {
initWith(getByName("release"))
}
}

compileOptions {
Expand Down
61 changes: 7 additions & 54 deletions app/postbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
# - Python 2.7.15
# - Python 3.7.0
#
# Command line:
# gradlew postbuildscript
#

SUPPORTED_PYTHON_PLATFORMS = ['Windows', 'Linux', 'Darwin']

Expand Down Expand Up @@ -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 #
Expand All @@ -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)
Original file line number Diff line number Diff line change
@@ -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;

}
19 changes: 19 additions & 0 deletions app/src/gplay/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.nutomic.syncthingandroid">

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove" />

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" tools:node="remove"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" tools:node="merge"/>

<application>
<service
android:name=".service.SyncthingService"
android:foregroundServiceType="dataSync"
tools:node="replace"
/>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -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;

}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,9 +18,14 @@ public class ReceiverManager {

private static List<BroadcastReceiver> mReceivers = new ArrayList<BroadcastReceiver>();

@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);
}

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -517,4 +517,4 @@
<string name="no_versioning_description">Escolha um tipo de versionamento para habilitá-lo.</string>
<string name="type_simple">Tipo: Simples</string>
<string name="type_trashcan">Tipo: Lixo</string>
</resources>
</resources>
7 changes: 0 additions & 7 deletions app/src/release/AndroidManifest.xml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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;

}
3 changes: 3 additions & 0 deletions git-log.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@echo off
git log > "X:\git.log"
start "" "X:\git.log"
8 changes: 4 additions & 4 deletions postbuild_copy_apk.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ 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%
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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 05d91f7

Please sign in to comment.