我目前正在考虑将我开始使用react-native开发的应用程序移植到codenameone。为此,我仍在检查可行性和所需的工作量(因为我不得不移植或开发一些从react-native到codenameone的本机库绑定,因为codenameone缺少了我的一些需求,例如对socket.io的支持例)。免费的Codenameone构建云服务beeing仅限于1Mb的应用程序,我必须在本地进行测试构建(只有少数测试类,并且使用了Google Maps cn1lib,我的测试应用程序已超过1Mb限制)
遗憾的是,在codenameone上没有关于如何执行本地构建的免费文档,实际上我在Internet上找不到有关如何执行此操作的任何说明(我仅在博客文章中找到了有关如何执行本地构建的一些基本且不推荐使用的说明本地iOS版本,但不适用于Android)。所以我必须自己弄清楚...
在花了一段时间研究Gradle配置参数之后,我终于成功构建了一个可在我的android测试设备上运行的基本codenameone应用程序区域设置。但是问题是,当我添加一个外部cn1lib(谷歌映射本机cn1lib https://github.com/codenameone/codenameone-google-maps)时,我的应用程序错误是由该lib决定的。
在android错误日志中,我可以找到以下消息:

D/MyApplication(  551): [EDT] 0:0:0,99 - Exception: java.lang.ClassCastException - com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface
W/System.err(  551): java.lang.ClassCastException: com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface
W/System.err(  551):    at com.codename1.system.NativeLookup.create(Unknown Source)
W/System.err(  551):    at com.codename1.googlemaps.MapContainer.<init>(MapContainer.java:171)
W/System.err(  551):    at com.codename1.googlemaps.MapContainer.<init>(MapContainer.java:151)
W/System.err(  551):    at com.tbdlab.testapp.MyApplication.start(MyApplication.java:207)
W/System.err(  551):    at com.tbdlab.testapp.MyApplicationStub.run(MyApplicationStub.java:183)
W/System.err(  551):    at com.codename1.ui.Display.processSerialCalls(Unknown Source)
W/System.err(  551):    at com.codename1.ui.Display.mainEDTLoop(Unknown Source)
W/System.err(  551):    at com.codename1.ui.RunnableWrapper.run(Unknown Source)
W/System.err(  551):    at com.codename1.impl.CodenameOneThread$1.run(Unknown Source)
W/System.err(  551):    at java.lang.Thread.run(Thread.java:818)


我真的不明白为什么当我查看已编译的apk的dex文件时,为什么InternalNativeMapsImpl无法转换为NativeInterface,并且正确包含了Google地图cn1lib的所有必需类(对于android)(所以我有com.codenameone.googlemaps.InternalNativeMapscom.codenameone.googlemaps.InternalNativeMapsImplcom.codenameone.googlemaps.MapContainer)以及它们所依赖的codenameone本机接口类(com.codename1.system.NativeInterfacecom.codename1.impl.android.LifecycleListener ...)。并且我对其进行了反编译,并且代码是正确的(无论如何我都不使用任何混淆方法,因此没有真正的理由说明编译后的代码与源代码会有所不同)。我可能在这里缺少使用cn1lib构建本地codenameone的功能。

那么,有没有人已经通过使用执行本机绑定的cn1lib成功地进行了本地构建?如果是,确切的程序是什么?
我真的希望有人能够提供帮助,因为在这一点上,我正在认真考虑坚持使用本机响应(我很高兴,因为它并非完全是本机,这一事实我还是很高兴的)或跳进去(或kotlin本机),即使我仍然认为codenameone比其他解决方案具有许多优势(但对开发阶段无法执行本地构建只是一个完全的尝试)

最佳答案

如前所述,在我的一些测试(使用我需要的全套cn1lib +一些自定义库)中,我已经超过了1Mb的限制(服务器因此拒绝了我的测试版本)。因此,在开发阶段使用免费的构建云服务器不是我的选择(无论如何,如果不确定是否可以完全独立,我将不会使用任何解决方案。要进行发布,我当然会订阅)并使用cloud buid服务器,因为它比本地服务器方便得多,而且我不拥有Mac电脑(我只有一台可测试的iphone),并且想要制作一些iOS版本时需要借用一台; )。但是我想确定,如果由于某种原因您的服务消失了,我仍然可以进行构建。此外,我看不到在应用程序的开发阶段(可能要花我几个月的时间)支付订阅的意义,尤其是因为我不确定我是否会使用codenameone作为最终解决方案(我仍然必须检查工作,它需要将我已经有的一些本地库改编为codenameone)。这就是为什么我尝试进行本地构建的原因。

关于so​​cket.io库,我已经开始创建一个cn1lib,它将使用本机解决方案(对于Android为https://github.com/socketio/socket.io-client-java,对于iOS为https://github.com/socketio/socket.io-client-swift,对于javascript是原始的socket.io库)。这并不是真正的问题,它只是给出一个示例,如果我想从react-native切换到该数据库,我必须在codenameone中创建。

关于cn1lib的工作原理,我已经弄清楚了,我将cn1 google-maps lib的所有必需类都包含在了我的android项目中(因此,我将main.zip,nativeand.zip和stubs.zip中的内容包括在内项目),并在生成的apk的.dex文件中检查它们是否已正确包装在其中(如前所述)。所以我的问题似乎不是我忘记在我的项目中包括cn1lib的某个类,而是别的了。错误消息是:Exception: java.lang.ClassCastException - com.codename1.googlemaps.InternalNativeMapsImpl cannot be cast to com.codename1.system.NativeInterface,所以它不是指未找到的类,而是强制转换的异常。。。我真的不知道什么会导致此问题。我从这里 codenameone核心类
https://github.com/codenameone/CodenameOne/tree/master/CodenameOne/src/ https://github.com/codenameone/CodenameOne/tree/master/Ports/Android

将它们包括在我的项目中,所以我想我没有错过任何一个。并且在构建不使用cn1lib的项目(例如简单的“ hello word”应用程序)时,它可以在我的android测试设备上编译并正常运行。
问题确实出在我的应用尝试创建googlemap视图时,它返回强制转换异常(然后默认尝试创建html浏览器mapview并由于缺少一些html文件而在此处失败)。
因此,这可能是一个配置问题(编译器将其用作本机类文件的Java版本可能已经在cn1lib main.zip文件中进行编译了吗?)
这是我使用的gradle构建文件:

buildscript {
        repositories {
            jcenter()
            maven { url "https://plugins.gradle.org/m2/" }
            google()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:3.0.1'
            classpath 'me.tatarka:gradle-retrolambda:3.2.0'
        }
    }


    allprojects {
        repositories {
            jcenter()
            google()
        }
    }

    apply plugin: 'com.android.application'
    apply plugin: 'me.tatarka.retrolambda'


    android {
        compileSdkVersion 26
        buildToolsVersion '26.0.2'
        dexOptions {
            // Prevent OutOfMemory with MultiDex during the build phase
            javaMaxHeapSize "4g"
        }
        lintOptions {
            checkReleaseBuilds false
        }

        defaultConfig {
            applicationId "com.tbdlab.testapp"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
            multiDexEnabled true
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' //my proguard files are actually empty so no obfuscation is performed. I checked it in the generated apk
            }
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7//.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_7//.VERSION_1_8
        }
    }
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
                exclude group: 'com.android.support', module: 'support-annotations'
            })
        compile 'com.google.android.gms:play-services:9.4.0' //compile 'com.google.android.gms:play-services-maps:11.8.0'
        compile 'com.android.support:multidex:1.0.1'
    }


这是我的AndroidManifest.xml文件,其中包含cn1lib中定义的所有权限:




<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--- Permissions requiered by the google maps cn1lib -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>

<application android:allowBackup="true"  android:icon="@drawable/icon" android:label="MyApplication" android:name="android.support.multidex.MultiDexApplication">
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="...masked_it_but_put_my_correct_key_here..."/>
<activity  android:label="MyApplication" android:launchMode="singleTop" android:name="com.tbdlab.testapp.MyApplicationStub" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>
<receiver android:name="com.codename1.impl.android.LocalNotificationPublisher"/>
<service android:exported="false" android:name="com.codename1.impl.android.BackgroundFetchHandler"/>
<activity android:name="com.codename1.impl.android.CodenameOneBackgroundFetchActivity" android:theme="@android:style/Theme.NoDisplay"/>
<activity android:name="com.codename1.location.CodenameOneBackgroundLocationActivity" android:theme="@android:style/Theme.NoDisplay"/>
<service android:exported="false" android:name="com.codename1.location.BackgroundLocationHandler"/>
<service android:exported="false" android:name="com.codename1.location.GeofenceHandler"/>
<service android:exported="false" android:name="com.codename1.media.AudioService"/>
<activity android:excludeFromRecents="true" android:exported="false" android:name="com.google.android.gms.auth.api.signin.internal.SignInHubActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<provider android:authorities="com.tbdlab.testapp.google_measurement_service" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementContentProvider"/>
<receiver android:enabled="true" android:name="com.google.android.gms.measurement.AppMeasurementReceiver">
    <intent-filter>
        <action android:name="com.google.android.gms.measurement.UPLOAD"/>
    </intent-filter>
</receiver>
<service android:enabled="true" android:exported="false" android:name="com.google.android.gms.measurement.AppMeasurementService"/>
<activity android:name="com.google.android.gms.ads.AdActivity" android:theme="@android:style/Theme.Translucent"/>






我真的看不到什么会导致强制转换异常,但是由于缺少有关如何创建本地版本的基础教程,我可能会错过一些东西,甚至都不知道。

对于此测试,我制作了一个非常简单的应用程序,而不是仅显示本地google地图,它可以在模拟器中正确运行并在构建云服务器上编译,并且在我的android测试设备中运行良好。因此,问题出在我的gradle构建配置中(或者即使我认为它对JVM没有任何影响,也可能是AndroidManifest.xml文件),或者是我包含在本地项目的android项目中的codenameone核心和cn1lib中。

关于android - 在本地代号Android构建中包含cn1lib?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49224784/

10-11 17:16