build: compile release APK and update dependencies (expo-image-manipulator/loader)

This commit is contained in:
2026-05-31 14:24:26 +02:00
parent 69637c4203
commit 2b5a259fe5
1260 changed files with 3804 additions and 166620 deletions
+2
View File
@@ -0,0 +1,2 @@
<manifest>
</manifest>
@@ -0,0 +1,105 @@
package expo.modules.imageloader
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import expo.modules.core.interfaces.InternalModule
import expo.modules.interfaces.imageloader.ImageLoaderInterface
import java.util.concurrent.ExecutionException
import java.util.concurrent.Future
class ImageLoaderModule(val context: Context) : InternalModule, ImageLoaderInterface {
override fun getExportedInterfaces(): List<Class<*>> {
return listOf(ImageLoaderInterface::class.java)
}
override fun loadImageForDisplayFromURL(url: String): Future<Bitmap> {
val future = SimpleSettableFuture<Bitmap>()
loadImageForDisplayFromURL(
url,
object : ImageLoaderInterface.ResultListener {
override fun onSuccess(bitmap: Bitmap) = future.set(bitmap)
override fun onFailure(cause: Throwable?) =
future.setException(ExecutionException(cause))
}
)
return future
}
override fun loadImageForDisplayFromURL(
url: String,
resultListener: ImageLoaderInterface.ResultListener
) {
Glide.with(context)
.asBitmap()
.load(url)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
resultListener.onSuccess(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
// no op
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
resultListener.onFailure(Exception("Loading bitmap failed"))
}
})
}
override fun loadImageForManipulationFromURL(url: String): Future<Bitmap> {
val future = SimpleSettableFuture<Bitmap>()
loadImageForManipulationFromURL(
url,
object : ImageLoaderInterface.ResultListener {
override fun onSuccess(bitmap: Bitmap) = future.set(bitmap)
override fun onFailure(cause: Throwable?) = future.setException(ExecutionException(cause))
}
)
return future
}
override fun loadImageForManipulationFromURL(
url: String,
resultListener: ImageLoaderInterface.ResultListener
) {
val normalizedUrl = normalizeAssetsUrl(url)
Glide.with(context)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.load(normalizedUrl)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
resultListener.onSuccess(resource)
}
override fun onLoadCleared(placeholder: Drawable?) {
// no op
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
resultListener.onFailure(Exception("Loading bitmap failed"))
}
})
}
private fun normalizeAssetsUrl(url: String): String {
var actualUrl = url
if (url.startsWith("asset:///")) {
actualUrl = "file:///android_asset/" + url.split("/").last()
}
return actualUrl
}
}
@@ -0,0 +1,9 @@
package expo.modules.imageloader
import android.content.Context
import expo.modules.core.BasePackage
import expo.modules.core.interfaces.InternalModule
class ImageLoaderPackage : BasePackage() {
override fun createInternalModules(context: Context): List<InternalModule> = listOf(ImageLoaderModule(context))
}
@@ -0,0 +1,120 @@
// Copied from React Native
package expo.modules.imageloader;
import androidx.annotation.Nullable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* A super simple Future-like class that can safely notify another Thread when a value is ready.
* Does not support canceling.
*/
public class SimpleSettableFuture<T> implements Future<T> {
private final CountDownLatch mReadyLatch = new CountDownLatch(1);
private @Nullable
T mResult;
private @Nullable
Exception mException;
/**
* Sets the result. If another thread has called {@link #get}, they will immediately receive the
* value. set or setException must only be called once.
*/
public void set(@Nullable T result) {
checkNotSet();
mResult = result;
mReadyLatch.countDown();
}
/**
* Sets the exception. If another thread has called {@link #get}, they will immediately receive
* the exception. set or setException must only be called once.
*/
public void setException(Exception exception) {
checkNotSet();
mException = exception;
mReadyLatch.countDown();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
throw new UnsupportedOperationException();
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return mReadyLatch.getCount() == 0;
}
@Override
public @Nullable
T get() throws InterruptedException, ExecutionException {
mReadyLatch.await();
if (mException != null) {
throw new ExecutionException(mException);
}
return mResult;
}
/**
* Wait up to the timeout time for another Thread to set a value on this future. If a value has
* already been set, this method will return immediately.
*
* <p>NB: For simplicity, we catch and wrap InterruptedException. Do NOT use this class if you are
* in the 1% of cases where you actually want to handle that.
*/
@Override
public @Nullable
T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (!mReadyLatch.await(timeout, unit)) {
throw new TimeoutException("Timed out waiting for result");
}
if (mException != null) {
throw new ExecutionException(mException);
}
return mResult;
}
/**
* Convenience wrapper for {@link #get()} that re-throws get()'s Exceptions as RuntimeExceptions.
*/
public @Nullable
T getOrThrow() {
try {
return get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Convenience wrapper for {@link #get(long, TimeUnit)} that re-throws get()'s Exceptions as
* RuntimeExceptions.
*/
public @Nullable
T getOrThrow(long timeout, TimeUnit unit) {
try {
return get(timeout, unit);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e);
}
}
private void checkNotSet() {
if (mReadyLatch.getCount() == 0) {
throw new RuntimeException("Result has already been set!");
}
}
}