Poll: Whether to keep Android APIs

The SubstrateVM based backend does not come with Android APIs, and those APIs will take a lot of effort to port to the new VM. Please vote accordingly and carefully:

  • My app does not use any Android APIs
  • My app uses some Android APIs and can be updated to an alternative
  • My app relies on Android APIs and is impossible to switch to an alternative

0 voters

And if you need those Android APIs, please comment below about which API you are using so I could put effort on things that really matters.

Just a quick note: most of the offered Android APIs are there “by accident”: because they were used / required the Android implementation of the Java standard library.

I think it would be safe to assume that these APIs will not be supported going forward (especially with the SubstrateVM backend). If a specific Android API is useful for many users, then a now moe-android module could be provided with these APIs (like e.g. android.database)

Yes the main consideration is the database api as my own app uses that :wink: But it shouldn’t be hard to replace it with the pure sqlite java library.

Yes, not so hard. I created ORM library that have the same interface in Android and iOS. On iOS implementation it use org.sqlite.c. I think I can share everything as a library on GitHub if need.
Here is some usefull POC of using pure sqlite.

package com.stayfit.queryorm.lib.ios;

import com.stayfit.queryorm.lib.TypeConverter;

import org.moe.natj.general.ptr.Ptr;
import org.moe.natj.general.ptr.VoidPtr;
import org.moe.natj.general.ptr.impl.PtrFactory;
import org.sqlite.c.Globals;

import java.util.Date;

public class SQLiteStatement {

private final int SQL_OK = 0;
private final int SQL_ROW = 100;
private final int SQL_DONE = 101;

private final String statement;

private final Object[] bindArgs;

private VoidPtr stmtHandle;

private VoidPtr dbHandle;

private String lastError;

private int affectedCount = 0;

private long lastInsertedID = -1;

VoidPtr getStmtHandle() {
    return stmtHandle;
}

VoidPtr getDbHandle() {
    return dbHandle;
}

String getLastError() {
    return lastError;
}

public SQLiteStatement(String statement, Object[] bindArgs) {
    if (statement == null) {
        throw new NullPointerException();
    }
    this.statement = statement;
    this.bindArgs = bindArgs == null ? new Object[0] : bindArgs;
}

public boolean prepare(VoidPtr dbHandle) {
    if (dbHandle == null) {
        throw new NullPointerException();
    }
    this.dbHandle = dbHandle;

    @SuppressWarnings("unchecked") Ptr<VoidPtr> stmtRef = (Ptr<VoidPtr>) PtrFactory
            .newPointerPtr(Void.class, 2, 1, true, false);
    int err = Globals.sqlite3_prepare_v2(dbHandle, statement, -1, stmtRef, null);
    if (err != 0) {
        lastError = Globals.sqlite3_errmsg(dbHandle);
        return false;
    }

    stmtHandle = stmtRef.get();
    int idx = 0;
    for (Object bind : bindArgs) {
        idx++;
        if (bind instanceof String) {
            err = Globals.sqlite3_bind_text(stmtHandle, idx, (String) bind, -1, null);
        } else if (bind instanceof Integer) {
            err = Globals.sqlite3_bind_int(stmtHandle, idx, (Integer) bind);
        } else if (bind instanceof Long) {
            err = Globals.sqlite3_bind_int64(stmtHandle, idx, (Long) bind);
        } else if (bind instanceof Double) {
            err = Globals.sqlite3_bind_double(stmtHandle, idx, (Double) bind);
        } else if (bind instanceof Float) {
            err = Globals.sqlite3_bind_double(stmtHandle, idx, (Float) bind);
        } else if (bind instanceof Boolean) {
            err = Globals.sqlite3_bind_int(stmtHandle, idx, ((Boolean) bind) ? 1 : 0);
        } else if (bind instanceof Date) {
            String value = new TypeConverter().writeDateTime((Date)bind);
            err = Globals.sqlite3_bind_text(stmtHandle, idx, value, -1, null);
        } else if (bind == null) {
            err = Globals.sqlite3_bind_null(stmtHandle, idx);
        } else {
            lastError = "No implemented SQLite3 bind function found for " + bind.getClass()
                    .getName();
            return false;
        }
        if (err != 0) {
            lastError = Globals.sqlite3_errmsg(dbHandle);
            return false;
        }
    }
    return true;
}

public boolean exec() {
    if (stmtHandle == null) {
        throw new RuntimeException("statement handle is closed");
    }
    int err = Globals.sqlite3_step(stmtHandle);
    if (err == SQL_ROW || err == SQL_DONE) {
        affectedCount = Globals.sqlite3_changes(dbHandle);
        lastInsertedID = Globals.sqlite3_last_insert_rowid(dbHandle);
    }
    if (err != SQL_DONE && err != SQL_ROW) {
        lastError = Globals.sqlite3_errmsg(dbHandle);
        close();
        return false;
    }

    close();
    return true;
}

public SQLiteCursor query() {
    return new SQLiteCursor(this);
}

void close() {
    if (stmtHandle != null) {
        Globals.sqlite3_finalize(stmtHandle);
        stmtHandle = null;
        dbHandle = null;
    }
}

boolean step() {
    if (stmtHandle == null) {
        throw new RuntimeException("statement handle is closed");
    }
    int err = Globals.sqlite3_step(stmtHandle);
    if (err != SQL_ROW) {
        lastError = Globals.sqlite3_errmsg(dbHandle);
        return false;
    }
    return true;
}

boolean reset() {
    if (stmtHandle == null) {
        throw new RuntimeException("statement handle is closed");
    }
    return Globals.sqlite3_reset(stmtHandle) == SQL_OK;
}

public String getStatement() {
    return statement;
}

public int getAffectedCount() {
    return affectedCount;
}

public long getLastInsertedID() {
    return lastInsertedID;
}
}
1 Like

I use next android libs:
android.util.Log;
android.util.Base64;
android.os.SystemClock;
android.util.ArrayMap;
android.util.SparseBooleanArray;

I’d love to look at your ORM implementation. Are you using some existing sqlite cocoapod?

1 Like

The new SVM based MOE will come with javesqlite built in (that’s the current plan). Also iOS SDK has built in sqlite 3 support and you can generate java bindings to those APIs, see https://doc.multi-os-engine.org/multi-os-engine/7_creating_db_app/2_part2/part2.html and https://github.com/multi-os-engine/moe-samples-java/tree/moe-master/MuseumMap/ios/src/main/java/org/sqlite

1 Like

I think these can be replaced relatively easily.

Thank you for reminder about those. I’ve read those tutorials while back, but completely forgot about all that stuff.