将iOS Objective-c应用程序移植到Android Java

时间:2012-12-29 12:57:49

标签: android ios

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

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

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

由于通信特定于Core Bluetooth API,因此必须为Android重新编写。 ui层应该很容易随便移动,因为它完全取决于Phonegap。然而,对于持久性和逻辑层,我正在寻找一种方法来将它们自动转换为Android,或者以可重用于两个平台的方式重新编写它们。

一种方法可以是将相关代码从Objective C自动转换为Java。非UI类有converter to go from Java to objective C个。

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

4 个答案:

答案 0 :(得分:7)

似乎有: http://code.google.com/p/objc2j/

可以通过http://objc2j.googlecode.com/svn/

访问存储库

我自己没有检查过,所以请发表您的意见。

答案 1 :(得分:5)

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

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

Java to Objective C:http://code.google.com/p/j2objc/

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

祝你好运!

答案 2 :(得分:2)

最好的办法是使用Apportable。它是一个提供clang端口,objective-c运行时以及iOS上大多数框架(包括UIKit)的平台。

还没有Core Bluetooth包装器,但您可以从他们的平台调用java API。 FMDatabase可以正常工作,理论上电话间隙界面应该可以正常工作。

我会避免代码生成器的建议。如果你有一种显着的代码库,他们最终会花很多时间重新实现你已经构建的所有内容。

答案 3 :(得分:0)

我已经将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,这就是我最终得到的......

FMDatabase:

out.flush();

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
    }

}