Use product flavors to provide marshmallow support (#57)

* Use product flavors to provide marshmallow support

Fix crashing when opening archives

* Fix artifacts upload

* Change artifact names

* Fix app updater
This commit is contained in:
FooIbar authored and GitHub committed 2023-10-14 19:14:19 +00:00
1 parent e29281ce39
commit f2d94f1ed6
14 files changed
+211 -100

No files matched your search

+48 -12
View File
@@ -63,35 +63,71 @@ jobs:
- name: Update ARM64
uses: actions/upload-artifact@v3
with:
name: arm64-v8a-${{ github.sha }}
path: app/build/outputs/apk/release/app-arm64-v8a-release.apk
name: default-arm64-v8a-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-arm64-v8a-release.apk
- name: Update x86_64
uses: actions/upload-artifact@v3
with:
name: x86_64-${{ github.sha }}
path: app/build/outputs/apk/release/app-x86_64-release.apk
name: default-x86_64-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-x86_64-release.apk
- name: Update ARM32
uses: actions/upload-artifact@v3
with:
name: armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/release/app-armeabi-v7a-release.apk
name: default-armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-armeabi-v7a-release.apk
- name: Update x86
uses: actions/upload-artifact@v3
with:
name: x86-${{ github.sha }}
path: app/build/outputs/apk/release/app-x86-release.apk
name: default-x86-${{ github.sha }}
path: app/build/outputs/apk/default/release/app-default-x86-release.apk
- name: Update mapping
uses: actions/upload-artifact@v3
with:
name: mapping-${{ github.sha }}
path: app/build/outputs/mapping/release/mapping.txt
name: default-mapping-${{ github.sha }}
path: app/build/outputs/mapping/defaultRelease/mapping.txt
- name: Update native debug symbols
uses: actions/upload-artifact@v3
with:
name: native-debug-symbols-${{ github.sha }}
path: app/build/outputs/native-debug-symbols/release/native-debug-symbols.zip
name: default-native-debug-symbols-${{ github.sha }}
path: app/build/outputs/native-debug-symbols/defaultRelease/native-debug-symbols.zip
- name: Update Marshmallow ARM64
uses: actions/upload-artifact@v3
with:
name: marshmallow-arm64-v8a-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-arm64-v8a-release.apk
- name: Update Marshmallow x86_64
uses: actions/upload-artifact@v3
with:
name: marshmallow-x86_64-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-x86_64-release.apk
- name: Update Marshmallow ARM32
uses: actions/upload-artifact@v3
with:
name: marshmallow-armeabi-v7a-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-armeabi-v7a-release.apk
- name: Update Marshmallow x86
uses: actions/upload-artifact@v3
with:
name: marshmallow-x86-${{ github.sha }}
path: app/build/outputs/apk/marshmallow/release/app-marshmallow-x86-release.apk
- name: Update Marshmallow mapping
uses: actions/upload-artifact@v3
with:
name: marshmallow-mapping-${{ github.sha }}
path: app/build/outputs/mapping/marshmallowRelease/mapping.txt
- name: Update Marshmallow native debug symbols
uses: actions/upload-artifact@v3
with:
name: marshmallow-native-debug-symbols-${{ github.sha }}
path: app/build/outputs/native-debug-symbols/marshmallowRelease/native-debug-symbols.zip
+28 -12
View File
@@ -45,21 +45,37 @@ jobs:
- name: Rename Apks
run: |
cp app/build/outputs/apk/release/app-universal-release.apk app/build/outputs/apk/release/EhViewer-universal.apk
cp app/build/outputs/apk/release/app-arm64-v8a-release.apk app/build/outputs/apk/release/EhViewer-arm64-v8a.apk
cp app/build/outputs/apk/release/app-x86_64-release.apk app/build/outputs/apk/release/EhViewer-x86_64.apk
cp app/build/outputs/apk/release/app-x86-release.apk app/build/outputs/apk/release/EhViewer-x86.apk
cp app/build/outputs/apk/release/app-armeabi-v7a-release.apk app/build/outputs/apk/release/EhViewer-armeabi-v7a.apk
mv app/build/outputs/apk/default/release/app-default-universal-release.apk EhViewer-default-universal.apk
mv app/build/outputs/apk/default/release/app-default-arm64-v8a-release.apk EhViewer-default-arm64-v8a.apk
mv app/build/outputs/apk/default/release/app-default-x86_64-release.apk EhViewer-default-x86_64.apk
mv app/build/outputs/apk/default/release/app-default-x86-release.apk EhViewer-default-x86.apk
mv app/build/outputs/apk/default/release/app-default-armeabi-v7a-release.apk EhViewer-default-armeabi-v7a.apk
mv app/build/outputs/mapping/defaultRelease/mapping.txt default-mapping.txt
mv app/build/outputs/native-debug-symbols/defaultRelease/native-debug-symbols.zip default-native-debug-symbols.zip
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-universal-release.apk EhViewer-marshmallow-universal.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-arm64-v8a-release.apk EhViewer-marshmallow-arm64-v8a.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-x86_64-release.apk EhViewer-marshmallow-x86_64.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-x86-release.apk EhViewer-marshmallow-x86.apk
mv app/build/outputs/apk/marshmallow/release/app-marshmallow-armeabi-v7a-release.apk EhViewer-marshmallow-armeabi-v7a.apk
mv app/build/outputs/mapping/marshmallowRelease/mapping.txt marshmallow-mapping.txt
mv app/build/outputs/native-debug-symbols/marshmallowRelease/native-debug-symbols.zip marshmallow-native-debug-symbols.zip
- name: Releases
uses: softprops/action-gh-release@v1
with:
body: Bump Version
files: |
app/build/outputs/apk/release/EhViewer-universal.apk
app/build/outputs/apk/release/EhViewer-arm64-v8a.apk
app/build/outputs/apk/release/EhViewer-x86_64.apk
app/build/outputs/apk/release/EhViewer-x86.apk
app/build/outputs/apk/release/EhViewer-armeabi-v7a.apk
app/build/outputs/mapping/release/mapping.txt
app/build/outputs/native-debug-symbols/release/native-debug-symbols.zip
EhViewer-default-universal.apk
EhViewer-default-arm64-v8a.apk
EhViewer-default-x86_64.apk
EhViewer-default-x86.apk
EhViewer-default-armeabi-v7a.apk
default-mapping.txt
default-native-debug-symbols.zip
EhViewer-marshmallow-universal.apk
EhViewer-marshmallow-arm64-v8a.apk
EhViewer-marshmallow-x86_64.apk
EhViewer-marshmallow-x86.apk
EhViewer-marshmallow-armeabi-v7a.apk
marshmallow-mapping.txt
marshmallow-native-debug-symbols.zip
+21 -3
View File
@@ -62,7 +62,7 @@ android {
defaultConfig {
applicationId = "moe.tarsin.ehviewer"
minSdk = 23
minSdk = 28
targetSdk = 34
versionCode = 180043
versionName = "1.8.10.0-SNAPSHOT"
@@ -89,6 +89,25 @@ android {
}
}
flavorDimensions += "api"
productFlavors {
create("default")
create("marshmallow") {
minSdk = 23
applicationIdSuffix = ".m"
versionNameSuffix = "-M"
externalNativeBuild {
cmake {
targets += "noop"
}
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
}
externalNativeBuild {
cmake {
path = File("src/main/cpp/CMakeLists.txt")
@@ -96,7 +115,6 @@ android {
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
@@ -288,7 +306,7 @@ spotless {
}
tasks.configureEach {
if (name == "mergeDebugJniLibFolders" || name == "mergeReleaseJniLibFolders") {
if (name.startsWith("merge") && name.endsWith("JniLibFolders")) {
dependsOn("cargoBuild")
// fix mergeDebugJniLibFolders UP-TO-DATE
inputs.dir(layout.buildDirectory.dir("rustJniLibs/android"))
+2
View File
@@ -78,3 +78,5 @@ include_directories(${libarchive_SOURCE_DIR}/libarchive)
# Build and link our app's native lib
add_library(${PROJECT_NAME} SHARED archive.c gifutils.c natsort/strnatcmp.c)
target_link_libraries(${PROJECT_NAME} archive_static log)
add_custom_target("noop")
+8 -8
View File
@@ -279,7 +279,7 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) {
}
JNIEXPORT jint JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_openArchive(JNIEnv *env, jclass thiz, jint fd,
Java_com_hippo_ehviewer_jni_ArchiveKt_openArchive(JNIEnv *env, jclass thiz, jint fd,
jlong size) {
EH_UNUSED(env);
EH_UNUSED(thiz);
@@ -359,7 +359,7 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_openArchive(JNIEnv *env, jcl
#pragma ide diagnostic ignored "UnreachableCode"
JNIEXPORT jobject JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToByteBuffer(JNIEnv *env, jclass thiz,
Java_com_hippo_ehviewer_jni_ArchiveKt_extractToByteBuffer(JNIEnv *env, jclass thiz,
jint index) {
EH_UNUSED(env);
EH_UNUSED(thiz);
@@ -389,7 +389,7 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToByteBuffer(JNIEnv *
#pragma clang diagnostic pop
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_closeArchive(JNIEnv *env, jclass thiz) {
Java_com_hippo_ehviewer_jni_ArchiveKt_closeArchive(JNIEnv *env, jclass thiz) {
EH_UNUSED(env);
EH_UNUSED(thiz);
for (int i = 0; i < CTX_POOL_SIZE; i++)
@@ -408,14 +408,14 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_closeArchive(JNIEnv *env, jc
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_needPassword(JNIEnv *env, jclass thiz) {
Java_com_hippo_ehviewer_jni_ArchiveKt_needPassword(JNIEnv *env, jclass thiz) {
EH_UNUSED(env);
EH_UNUSED(thiz);
return need_encrypt;
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_providePassword(JNIEnv *env, jclass thiz,
Java_com_hippo_ehviewer_jni_ArchiveKt_providePassword(JNIEnv *env, jclass thiz,
jstring str) {
EH_UNUSED(thiz);
struct archive_entry *entry;
@@ -446,7 +446,7 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_providePassword(JNIEnv *env,
}
JNIEXPORT jstring JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_getFilename(JNIEnv *env, jclass thiz,
Java_com_hippo_ehviewer_jni_ArchiveKt_getFilename(JNIEnv *env, jclass thiz,
jint index) {
EH_UNUSED(env);
EH_UNUSED(thiz);
@@ -462,7 +462,7 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_getFilename(JNIEnv *env, jcl
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToFd(JNIEnv *env, jclass thiz,
Java_com_hippo_ehviewer_jni_ArchiveKt_extractToFd(JNIEnv *env, jclass thiz,
jint index, jint fd) {
EH_UNUSED(env);
EH_UNUSED(thiz);
@@ -477,7 +477,7 @@ Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_extractToFd(JNIEnv *env, jcl
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_gallery_ArchivePageLoaderKt_releaseByteBuffer(JNIEnv *env, jclass thiz,
Java_com_hippo_ehviewer_jni_ArchiveKt_releaseByteBuffer(JNIEnv *env, jclass thiz,
jobject buffer) {
EH_UNUSED(thiz);
void *addr = (*env)->GetDirectBufferAddress(env, buffer);
+4 -4
View File
@@ -46,21 +46,21 @@ static void doRewrite(byte *addr, size_t size) {
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_ehviewer_image_ImageKt_isGif(JNIEnv *env, jclass clazz, jint fd) {
Java_com_hippo_ehviewer_jni_GifUtilsKt_isGif(JNIEnv *env, jclass clazz, jint fd) {
byte buffer[GIF_HEADER_LENGTH];
return read(fd, buffer, GIF_HEADER_LENGTH) == GIF_HEADER_LENGTH &&
isGif(buffer);
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_image_ImageKt_rewriteGifSource(JNIEnv *env, jclass clazz, jobject buffer) {
Java_com_hippo_ehviewer_jni_GifUtilsKt_rewriteGifSource(JNIEnv *env, jclass clazz, jobject buffer) {
byte *addr = (*env)->GetDirectBufferAddress(env, buffer);
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
doRewrite(addr, size);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_ehviewer_image_ImageKt_mmap(JNIEnv *env, jclass clazz, jint fd) {
Java_com_hippo_ehviewer_jni_GifUtilsKt_mmap(JNIEnv *env, jclass clazz, jint fd) {
struct stat64 st;
fstat64(fd, &st);
size_t size = st.st_size;
@@ -70,7 +70,7 @@ Java_com_hippo_ehviewer_image_ImageKt_mmap(JNIEnv *env, jclass clazz, jint fd) {
}
JNIEXPORT void JNICALL
Java_com_hippo_ehviewer_image_ImageKt_munmap(JNIEnv *env, jclass clazz, jobject buffer) {
Java_com_hippo_ehviewer_jni_GifUtilsKt_munmap(JNIEnv *env, jclass clazz, jobject buffer) {
byte *addr = (*env)->GetDirectBufferAddress(env, buffer);
size_t size = (*env)->GetDirectBufferCapacity(env, buffer);
munmap(addr, size);
@@ -81,7 +81,9 @@ class EhApplication : Application(), ImageLoaderFactory {
handler?.uncaughtException(t, e)
}
super.onCreate()
System.loadLibrary("ehviewer")
if (isAtLeastP) {
System.loadLibrary("ehviewer")
}
System.loadLibrary("ehviewer_rust")
ReadableTime.initialize(this)
lifecycleScope.launchIO {
@@ -13,14 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:RequiresApi(Build.VERSION_CODES.P)
package com.hippo.ehviewer.gallery
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.ParcelFileDescriptor
import android.util.Log
import androidx.annotation.RequiresApi
import com.hippo.ehviewer.Settings.archivePasswds
import com.hippo.ehviewer.image.Image
import com.hippo.ehviewer.jni.closeArchive
import com.hippo.ehviewer.jni.extractToByteBuffer
import com.hippo.ehviewer.jni.extractToFd
import com.hippo.ehviewer.jni.getFilename
import com.hippo.ehviewer.jni.needPassword
import com.hippo.ehviewer.jni.openArchive
import com.hippo.ehviewer.jni.providePassword
import com.hippo.ehviewer.jni.releaseByteBuffer
import com.hippo.ehviewer.util.FileUtils
import com.hippo.unifile.UniFile
import kotlinx.coroutines.CoroutineScope
@@ -169,12 +181,3 @@ class ArchivePageLoader(context: Context, private val uri: Uri, passwdFlow: Flow
}
private const val DEBUG_TAG = "ArchivePageLoader"
private external fun releaseByteBuffer(buffer: ByteBuffer)
private external fun openArchive(fd: Int, size: Long): Int
private external fun extractToByteBuffer(index: Int): ByteBuffer?
private external fun extractToFd(index: Int, fd: Int)
private external fun getFilename(index: Int): String
private external fun needPassword(): Boolean
private external fun providePassword(str: String): Boolean
private external fun closeArchive()
@@ -37,6 +37,10 @@ import coil.request.Options
import coil.size.Scale
import coil.size.Size
import com.hippo.ehviewer.R
import com.hippo.ehviewer.jni.isGif
import com.hippo.ehviewer.jni.mmap
import com.hippo.ehviewer.jni.munmap
import com.hippo.ehviewer.jni.rewriteGifSource
import com.hippo.ehviewer.util.isAtLeastO
import com.hippo.ehviewer.util.isAtLeastP
import com.hippo.ehviewer.util.isAtLeastU
@@ -198,8 +202,3 @@ class Image private constructor(drawable: Drawable, private val src: AutoCloseab
val source: ByteBuffer
}
}
external fun isGif(fd: Int): Boolean
external fun rewriteGifSource(buffer: ByteBuffer)
external fun mmap(fd: Int): ByteBuffer?
external fun munmap(buffer: ByteBuffer)
@@ -0,0 +1,16 @@
@file:RequiresApi(Build.VERSION_CODES.P)
package com.hippo.ehviewer.jni
import android.os.Build
import androidx.annotation.RequiresApi
import java.nio.ByteBuffer
external fun releaseByteBuffer(buffer: ByteBuffer)
external fun openArchive(fd: Int, size: Long): Int
external fun extractToByteBuffer(index: Int): ByteBuffer?
external fun extractToFd(index: Int, fd: Int)
external fun getFilename(index: Int): String
external fun needPassword(): Boolean
external fun providePassword(str: String): Boolean
external fun closeArchive()
@@ -0,0 +1,12 @@
@file:RequiresApi(Build.VERSION_CODES.P)
package com.hippo.ehviewer.jni
import android.os.Build
import androidx.annotation.RequiresApi
import java.nio.ByteBuffer
external fun isGif(fd: Int): Boolean
external fun rewriteGifSource(buffer: ByteBuffer)
external fun mmap(fd: Int): ByteBuffer?
external fun munmap(buffer: ByteBuffer)
@@ -79,6 +79,7 @@ import com.hippo.ehviewer.util.FileUtils
import com.hippo.ehviewer.util.getParcelableCompat
import com.hippo.ehviewer.util.getParcelableExtraCompat
import com.hippo.ehviewer.util.isAtLeastO
import com.hippo.ehviewer.util.isAtLeastP
import com.hippo.ehviewer.util.sendTo
import com.hippo.unifile.UniFile
import dev.chrisbanes.insetter.applyInsetter
@@ -196,54 +197,58 @@ class ReaderActivity : EhActivity() {
if (ACTION_EH == mAction) {
mGalleryInfo?.let { mGalleryProvider = EhPageLoader(it) }
} else if (Intent.ACTION_VIEW == mAction) {
if (mUri != null) {
try {
grantUriPermission(
BuildConfig.APPLICATION_ID,
mUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION,
)
} catch (e: Exception) {
Toast.makeText(this, R.string.error_reading_failed, Toast.LENGTH_SHORT).show()
}
if (isAtLeastP) {
if (mUri != null) {
try {
grantUriPermission(
BuildConfig.APPLICATION_ID,
mUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION,
)
} catch (e: Exception) {
Toast.makeText(this, R.string.error_reading_failed, Toast.LENGTH_SHORT).show()
}
val continuation: AtomicReference<Continuation<String>?> = AtomicReference(null)
mGalleryProvider = ArchivePageLoader(
this,
mUri!!,
flow {
if (!dialogShown) {
withUIContext {
dialogShown = true
dialog.run {
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val passwd = builder.text
if (passwd.isEmpty()) {
builder.setError(getString(R.string.passwd_cannot_be_empty))
} else {
continuation.getAndSet(null)?.resume(passwd)
val continuation: AtomicReference<Continuation<String>?> = AtomicReference(null)
mGalleryProvider = ArchivePageLoader(
this,
mUri!!,
flow {
if (!dialogShown) {
withUIContext {
dialogShown = true
dialog.run {
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val passwd = builder.text
if (passwd.isEmpty()) {
builder.setError(getString(R.string.passwd_cannot_be_empty))
} else {
continuation.getAndSet(null)?.resume(passwd)
}
}
setOnCancelListener {
finish()
}
}
setOnCancelListener {
finish()
}
}
}
}
while (true) {
currentCoroutineContext().ensureActive()
val r = suspendCancellableCoroutine {
continuation.set(it)
it.invokeOnCancellation { dialog.dismiss() }
while (true) {
currentCoroutineContext().ensureActive()
val r = suspendCancellableCoroutine {
continuation.set(it)
it.invokeOnCancellation { dialog.dismiss() }
}
emit(r)
withUIContext {
builder.setError(getString(R.string.passwd_wrong))
}
}
emit(r)
withUIContext {
builder.setError(getString(R.string.passwd_wrong))
}
}
},
)
},
)
}
} else {
Toast.makeText(this, "Archives are not supported before Android P", Toast.LENGTH_LONG).show()
}
}
}
@@ -1,9 +1,12 @@
package tachiyomi.data.release
import android.os.Build
import com.hippo.ehviewer.BuildConfig
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
val apkVariant = "${BuildConfig.FLAVOR}-${Build.SUPPORTED_ABIS[0]}"
/**
* Contains information about the latest release from GitHub.
*/
@@ -15,8 +18,9 @@ data class GithubRelease(
@SerialName("assets") val assets: List<GitHubAssets>,
) {
fun getDownloadLink(): String {
val apkVariant = Build.SUPPORTED_ABIS[0]
return (assets.find { it.downloadLink.contains(apkVariant) } ?: assets.find { it.downloadLink.contains("universal") } ?: assets[0]).downloadLink
val asset = assets.find { it.downloadLink.contains(apkVariant) }
?: assets.find { it.downloadLink.contains("${BuildConfig.FLAVOR}-universal") } ?: assets[0]
return asset.downloadLink
}
}
@@ -1,6 +1,5 @@
package tachiyomi.data.release
import android.os.Build
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -21,7 +20,6 @@ data class GithubArtifacts(
@SerialName("artifacts") val artifacts: List<GithubArtifact>,
) {
fun getDownloadLink(): String {
val apkVariant = Build.SUPPORTED_ABIS[0]
return (artifacts.find { it.name.contains(apkVariant) } ?: artifacts[0]).downloadLink
}
}