diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 8347d07..5b32ef7 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -68,11 +68,36 @@ jobs: path: app/src/main/libs/**/*.so if-no-files-found: warn + # AGP drives ndk-build, so the native inputs must be staged before ./gradlew (keeping + # that here rather than in a preBuild hook leaves Gradle offline-clean for local builds). + assemble: + name: assemble (AGP 8) + runs-on: ubuntu-24.04 + container: ghcr.io/xroche/httrack-android-build:latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive # MUST be recursive: coucal is nested in httrack + - name: Vendor libiconv + run: tools/ci/vendor-libiconv.sh + - name: Stage OpenSSL statics into prebuild/ + run: tools/ci/fetch-openssl-statics.sh # picks up $OPENSSL_ANDROID_ROOT from the image + - name: Gradle assemble + lint + run: ./gradlew --no-daemon assembleDebug assembleRelease lint + - uses: actions/upload-artifact@v4 + with: + name: apk + path: app/build/outputs/apk/**/*.apk + if-no-files-found: error + - uses: actions/upload-artifact@v4 + if: always() # the report is most useful when lint is unhappy + with: + name: lint-report + path: app/build/reports/lint-results-*.* + if-no-files-found: warn + # --- Phases below land with the app modernization (see the plan) --- # - # assemble: ./gradlew assembleDebug assembleRelease lint — needs the AGP 8 / - # AndroidX migration (Phase 3), and can use the GHCR toolchain image. - # # emulator-smoke: reactivecircus/android-emulator-runner (x86_64, api 21/29/34), # installs the APK and runs an instrumented crawl against a local fixture # server. Needs Phase 4 (storage) + the coffeecatch x86_64 fix. diff --git a/.gitignore b/.gitignore index 20210a6..713afae 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ workspace.xml /.gradle /local.properties /build -/gradle /.idea/libraries /app/.externalNativeBuild /app/build diff --git a/app/build.gradle b/app/build.gradle index 216fa4d..8b33630 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,39 +1,61 @@ -apply plugin: 'com.android.application' -android { - compileSdkVersion 11 - buildToolsVersion "25.0.2" - - defaultConfig { - applicationId "com.httrack.android" - minSdkVersion 9 - targetSdkVersion 25 - - ndk { - moduleName "libhtsjni" - abiFilters = [ "arm64-v8a", "x86_64" ] - } - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } - - dependencies { - // ContextCompat.checkSelfPermission needs version 23 - compile 'com.android.support:support-v4:23.0.0' - } - - productFlavors { - } - externalNativeBuild { - ndkBuild { - path 'src/main/jni/Android.mk' - } - } -} - -dependencies { -} \ No newline at end of file +plugins { + id 'com.android.application' +} + +android { + namespace 'com.httrack.android' + compileSdk 35 + // Pinned to what the toolchain image installs, so no build-tools are fetched at build time. + buildToolsVersion "35.0.0" + ndkVersion "26.3.11579264" + + defaultConfig { + applicationId "com.httrack.android" + minSdk 24 + // Left at master's value: 26 would silently drop the channel-less notifications, + // and 29 would take legacy storage away from the still File-based crawl. + targetSdk 25 + versionCode 63 + versionName "3.49.02.63" + + ndk { + abiFilters "arm64-v8a", "x86_64" + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + buildFeatures { + // HTTrackActivity reads BuildConfig.APPLICATION_ID for the FileProvider authority. + buildConfig true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + // This 2017-era code trips many modern checks; keep the build green and tighten later. + lint { + abortOnError false + } + + externalNativeBuild { + ndkBuild { + path 'src/main/jni/Android.mk' + } + } +} + +dependencies { + // Without this, coroutines' stale jdk7/jdk8 shims collide with the stdlib that absorbed them. + implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.22') + + implementation 'androidx.core:core:1.13.1' + implementation 'androidx.fragment:fragment:1.8.2' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..b2e1fde --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,2 @@ +# Native code resolves these reflectively, leaving R8 no Java caller to trace. +-keep class com.httrack.android.jni.** { *; } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2e1c279..53a8be9 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,13 +1,6 @@ - - + android:installLocation="auto" > @@ -27,7 +20,8 @@ android:theme="@style/AppTheme" > + android:label="@string/title_activity_startup" + android:exported="true" > @@ -42,10 +36,6 @@ android:name="com.httrack.android.OptionsActivity" android:label="@string/title_activity_options" > - - @@ -91,7 +81,7 @@ android:label="@string/title_activity_file_chooser" > diff --git a/app/src/main/java/com/httrack/android/HTTrackActivity.java b/app/src/main/java/com/httrack/android/HTTrackActivity.java index d4dc56e..a9e5c56 100755 --- a/app/src/main/java/com/httrack/android/HTTrackActivity.java +++ b/app/src/main/java/com/httrack/android/HTTrackActivity.java @@ -68,13 +68,6 @@ import android.os.Handler; import android.os.Parcelable; import android.os.StrictMode; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.NotificationCompat; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.FileProvider; import android.text.Editable; import android.text.Html; import android.text.TextUtils; @@ -96,6 +89,14 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; + import com.httrack.android.jni.HTTrackCallbacks; import com.httrack.android.jni.HTTrackLib; import com.httrack.android.jni.HTTrackStats; diff --git a/app/src/main/java/com/httrack/android/OptionsActivity.java b/app/src/main/java/com/httrack/android/OptionsActivity.java index 6c234df..9940131 100755 --- a/app/src/main/java/com/httrack/android/OptionsActivity.java +++ b/app/src/main/java/com/httrack/android/OptionsActivity.java @@ -31,6 +31,7 @@ import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.os.Parcelable; import android.util.DisplayMetrics; import android.util.Log; import android.view.Gravity; @@ -349,8 +350,11 @@ protected void onCreate(final Bundle savedInstanceState) { mapper.resetMap(); // Load map - mapper.unserialize(getIntent() - .getParcelableExtra("com.httrack.android.map")); + // Pinned to Parcelable: inlined, T infers as File & Parcelable and unserialize(File) + // matches just as well, which javac rejects as ambiguous. + final Parcelable savedMap = + getIntent().getParcelableExtra("com.httrack.android.map"); + mapper.unserialize(savedMap); Log.d(getClass().getSimpleName(), "map size: " + mapper.size()); // Create tabs diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml index c5fe882..93ebda3 100644 --- a/app/src/main/res/values-v11/styles.xml +++ b/app/src/main/res/values-v11/styles.xml @@ -4,7 +4,8 @@ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c74ff39..f8cccf6 100755 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -21,7 +21,8 @@ -