6

我的应用程序是一个医疗数据查看器,患者佩戴一个通过低功耗蓝牙传输数据的传感器。该应用程序是用 Objective C 开发的,针对 iOS 平台。现在需要将应用程序移植到 Android 平台。

目前iOS的设计和实现如下:

  • 通信 - Objective C,特定于核心蓝牙 API
  • 数据/持久性 - 目标 C,使用 FMDatabase 作为 SQLite 的接口
  • 算法/逻辑 - 目标 C
  • ui - 基于 Phonegap 的 JavaScript/HTML5

由于通信特定于 Core Bluetooth API,因此必须针对 Android 重新编写。ui 层应该易于移植,无需太多更改,因为它完全依赖于 Phonegap。然而,对于持久性和逻辑层,我正在寻找一种方法来自动将它们转换为 Android,或者以它们可在两个平台上重用的方式重新编写它们。

一种方法是自动将相关代码从 Objective C 转换为 Java。对于非 UI 类,有一个转换器可以从 Java 转换为 Objective C。

iOS/objective C 到 Android/Java 是否有类似的转换器?是否有其他可以使用的方法或框架?

4

4 回答 4

7

好像有: http ://code.google.com/p/objc2j/

该存储库应该可以通过http://objc2j.googlecode.com/svn/访问

自己没有查,所以请发表您对此的看法。

于 2012-12-29T13:02:26.930 回答
6

谷歌有一些开源项目可以做到这一点。

您将需要使用 SVN 来访问这些存储库。以下是链接:

Java 到目标 C: http ://code.google.com/p/j2objc/

目标 C 到 Java:http ://code.google.com/p/objc2j/

祝你好运!

于 2012-12-29T13:20:42.453 回答
2

你最好的选择是使用Apportable。它是一个提供 clang 端口、objective-c 运行时和 iOS 上的大多数框架(包括 UIKit)的平台。

目前还没有核心蓝牙包装器,但您可以为此从他们的平台调用 java API。FMDatabase 可以正常工作,Phone gap 接口理论上应该可以正常工作。

不过,我会避免使用代码生成器的建议。如果您有一种重要的代码库,他们最终会花费大量时间重新实现您已经构建的所有内容。

于 2013-05-23T21:35:21.153 回答
1

我在类似的场景中使用过O2J - Objective-C to Java Converter,效果很好。

无需太多工作,它将在您的算法/逻辑上做得很好。

它是可定制的,因此您可以为您的蓝牙代码添加自己的翻译。如果 API 的工作方式相同,您可以通过将蓝牙方法调用直接转换为 java 来获得,但它们可能不会。最好在您的 Objective-C 代码中为蓝牙添加一层间接层,以便真正轻松地提供 Android 特定的实现。例如创建一个BluetoothHelper.m 和一个BluetoothHelper.java,翻译会更顺畅。

我已经将它用于使用 FMDatabase 的项目。对于 FMDatabase 部分,我们已经将 FMDatabase/FMResultSet 作为间接层!我自己实现了 FMDatabase/FMResultSet,因为 sqlite Objective-c(基于 c 的 sqlite 函数)的 API 与 Android 太不同了。O2J 帮助我开始翻译 FMDatabase/FMResultSet,这就是我最终得到的...

调频数据库:

public class FMDatabase
{

    private SQLiteDatabase database;
    private HashMap<String, SQLiteStatement> compiled;

    public FMDatabase(SQLiteDatabase database)
    {
        this.database = database;
    }

    public FMResultSet executeQuery_arguments(String sql, Object... args)
    {

        synchronized (database)
        {
            String[] selectionArgs = objectArgsAsStrings(args);
            Cursor rawQuery = database.rawQuery(sql, selectionArgs);
            return new FMResultSet(rawQuery);
        }
    }

    public FMResultSet executeQuery(String sql, Object... args)
    {
        synchronized (database)
        {
            String[] selectionArgs = objectArgsAsStrings(args);
            Cursor rawQuery = database.rawQuery(sql, selectionArgs);
            return new FMResultSet(rawQuery);
        }
    }

    public String debugQuery(String sql, Object...args)
    {
        StringBuilder sb = new StringBuilder();
        FMResultSet rs = executeQuery(sql, args);
        rs.setupColumnNames();
        HashMap names = rs.columnNameToIndexMap();
        Set ks = names.keySet();
        for (Object k : ks)
        {
            sb.append(k);
            sb.append("\t");
        }
        sb.append("\n");
        while(rs.next())
        {
            for (Object k : ks)
            {
                String key = k.toString();
                if(rs.getType(key) == Cursor.FIELD_TYPE_STRING)
                {
                    sb.append(rs.stringForColumn(key));
                }
                else if(rs.getType(key) == Cursor.FIELD_TYPE_INTEGER)
                {
                    sb.append(rs.longForColumn(key));
                }
                else if(rs.getType(key) == Cursor.FIELD_TYPE_FLOAT)
                {
                    sb.append(rs.doubleForColumn(key));
                }
                else if(rs.getType(key) == Cursor.FIELD_TYPE_BLOB)
                {
                    sb.append(rs.stringForColumn(key));
                }
                else
                {
                    sb.append("<NOT STRING>");
                }
                sb.append("\t");
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    public String[] objectArgsAsStrings(Object... args)
    {
        String[] selectionArgs = new String[args.length];
        for (int i = 0; i < args.length; i++)
        {
            Object o = args[i];
            if(o instanceof Date)
            {
                selectionArgs[i] = Long.toString(((Date) o).getTime());
            }
            else if(o instanceof Boolean)
            {
                selectionArgs[i] = ((Boolean) o).booleanValue() ? "TRUE" : "FALSE";
            }
            else
            {
                selectionArgs[i] = args[i] == null ? "" : o.toString();
            }
        }
        return selectionArgs;
    }

    public boolean executeUpdate_arguments(String sql, Object... args)
    {
        synchronized (database)
        {
            String[] selectionArgs = objectArgsAsStrings(args);
            database.execSQL(sql, selectionArgs);
            return true;
        }
    }

    public boolean executeUpdate(String sql, Object... args)
    {
        synchronized (database)
        {
            SQLiteStatement statement = bindToCachedCompiledStatement(sql, args);
            statement.execute();
            return true;
        }
    }

    private SQLiteStatement bindToCachedCompiledStatement(String sql, Object... args)
    {
        HashMap<String, SQLiteStatement> statments = getCompiledStatements();
        SQLiteStatement statement = statments.get(sql);
        if (statement == null)
        {
            statement = database.compileStatement(sql);
            statments.put(sql, statement);
        }
        statement.clearBindings();
//      bindAllArgsAsStrings(statement, objectArgsAsStrings(args));
        bindAllArgs(statement, args);
        return statement;
    }

    private void bindAllArgs(SQLiteStatement statement, Object[] bindArgs)
    {
        if (bindArgs == null)
        {
            return;
        }
        int size = bindArgs.length;
        for (int i = 0; i < size; i++)
        {
            Object arg = bindArgs[i];
            int index = i + 1;
            if(arg == null)
            {
                statement.bindNull(index);
            }
            else if (arg instanceof String)
            {
                statement.bindString(index, (String) arg);
            }
            else if (arg instanceof Double || arg instanceof Float)
            {
                Number numArg = (Number) arg;
                statement.bindDouble(index, numArg.doubleValue());
            }
            else if (arg instanceof Integer || arg instanceof Long)
            {
                Number numArg = (Number) arg;
                statement.bindDouble(index, numArg.longValue());
            }
            else
            {
                statement.bindString(index, arg.toString());
            }
        }
    }

    public long executeInsert(String string, Object... args)
    {
        synchronized (database)
        {
            SQLiteStatement statement = bindToCachedCompiledStatement(string, args);
            try
            {
                return statement.executeInsert();
            }
            catch (Exception e)
            {
                Log.i("STD", "No Rows inserted", e);
                return 0;
            }
        }
    }

    public void bindAllArgsAsStrings(SQLiteStatement statement, String[] bindArgs)
    {
        if (bindArgs == null)
        {
            return;
        }
        int size = bindArgs.length;
        for (int i = 0; i < size; i++)
        {
            statement.bindString(i + 1, bindArgs[i]);
        }
    }

    private HashMap<String, SQLiteStatement> getCompiledStatements()
    {
        if (compiled == null)
        {
            compiled = new HashMap<String, SQLiteStatement>();
        }
        return compiled;
    }

    public boolean rollback()
    {
        synchronized (database)
        {
            database.execSQL("ROLLBACK;");
        }
        return true;
    }

    public boolean commit()
    {
        synchronized (database)
        {
            database.execSQL("COMMIT;");
        }
        return true;
    }

    public boolean beginDeferredTransaction()
    {
        synchronized (database)
        {
            database.execSQL("BEGIN DEFERRED TRANSACTION;");
        }
        return true;
    }

    public boolean beginTransaction()
    {
        synchronized (database)
        {
            database.execSQL("BEGIN EXCLUSIVE TRANSACTION;");
        }
        return true;
    }

    public boolean open()
    {
        return true;
    }

    public void setShouldCacheStatements(boolean shouldCacheStatements)
    {
        // TODO
    }

}

FM结果集:

public class FMResultSet
{
    private boolean columnNamesSetup;
    private HashMap<String, Number> columnNameToIndexMap;
    private Cursor rawQuery;

    public FMResultSet(Cursor rawQuery)
    {
        this.rawQuery = rawQuery;
    }

    public void close()
    {
        rawQuery.close();
    }

    public void setupColumnNames()
    {

        if (columnNameToIndexMap == null)
        {
            this.setColumnNameToIndexMap(new HashMap());
        }

        int columnCount = rawQuery.getColumnCount();

        int columnIdx = 0;
        for (columnIdx = 0; columnIdx < columnCount; columnIdx++)
        {
            columnNameToIndexMap.put(rawQuery.getColumnName(columnIdx).toLowerCase(), new Integer(columnIdx));
        }
        columnNamesSetup = true;
    }

    public boolean next()
    {
        return rawQuery.moveToNext();
    }

    public int columnIndexForName(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        columnName = columnName.toLowerCase();

        Number n = columnNameToIndexMap.get(columnName);

        if (n != null)
        {
            return NumberValueUtil.intVal(n);
        }

        Log.i("StdLog", String.format("Warning: I could not find the column named '%s'.", columnName));

        return -1;
    }

    public int intForColumn(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return 0;
        }

        return intForColumnIndex(columnIdx);
    }

    public int intForColumnIndex(int columnIdx)
    {
        return rawQuery.getInt(columnIdx);
    }

    public long longForColumn(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return 0;
        }

        return longForColumnIndex(columnIdx);
    }

    public long longForColumnIndex(int columnIdx)
    {
        return (long) rawQuery.getLong(columnIdx);
    }

    public boolean boolForColumn(String columnName)
    {
        return (this.intForColumn(columnName) != 0);
    }

    public boolean boolForColumnIndex(int columnIdx)
    {
        return (this.intForColumnIndex(columnIdx) != 0);
    }

    public double doubleForColumn(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return 0;
        }

        return doubleForColumnIndex(columnIdx);
    }

    public double doubleForColumnIndex(int columnIdx)
    {
        return rawQuery.getDouble(columnIdx);
    }

    public String stringForColumnIndex(int columnIdx)
    {
        return rawQuery.getString(columnIdx);
    }

    public String stringForColumn(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return null;
        }

        return this.stringForColumnIndex(columnIdx);
    }

    public Date dateForColumn(String columnName)
    {

        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return null;
        }

        return new Date((this.longForColumn(columnName)));
    }

    public Date dateForColumnIndex(int columnIdx)
    {
        return new Date((this.longForColumnIndex(columnIdx)));
    }

    public byte[] dataForColumn(String columnName)
    {
        if (!columnNamesSetup)
        {
            this.setupColumnNames();
        }

        int columnIdx = this.columnIndexForName(columnName);

        if (columnIdx == -1)
        {
            return null;
        }

        return this.dataForColumnIndex(columnIdx);
    }

    public byte[] dataForColumnIndex(int columnIdx)
    {

        return rawQuery.getBlob(columnIdx);
    }

    public HashMap columnNameToIndexMap()
    {
        return columnNameToIndexMap;
    }

    public void setColumnNameToIndexMap(HashMap value)
    {

        columnNameToIndexMap = value;
    }

    @SuppressLint("NewApi")
    public int getType(String string)
    {
        return rawQuery.getType(columnIndexForName(string));
    }

}
于 2015-05-06T15:00:25.810 回答