javafx - 如何定义gluon应用程序版本

标签 javafx gluon gluon-mobile

我想将应用程序版本放入我的 gluon 应用程序中。但我不知道该怎么办。我需要为此创建服务吗?

Screenshot

最佳答案

有一种非常简单的方法,不需要服务,但可能会导致错误:

您可以在 AndroidManifest 中维护 Android 的版本代码/版本号:

<?xml version="1.0" encoding="UTF-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
              package="your.package" 
              android:versionCode="1.1.0" 
              android:versionName="1.1.0">

在 iOS 上也是如此,在 Default-Info.plist 中:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>CFBundleIdentifier</key>
        <string>your.bundle.identifier</string>
        <key>CFBundleVersion</key>
        <string>1.1.0</string>

最后,您可以在代码中保留静态字段:

public static final String VERSION_NAME = "1.1.0";

例如,您可以从 NavigationDrawer 访问。

但是,这需要您每次发布新版本时手动更新。

为了避免错误,您可以设置一些 CI 作业来为您完成此操作。例如,参见这个 commit ,它是移动应用程序发布工作的一部分。

魅力下降服务

但是,避免已发布版本与代码中的变量之间不匹配的更明确方法是添加直接读取这些版本的服务。

类似这样的事情:

VersionService.java

package com.gluonhq.charm.down.plugins;

public interface VersionService {

    String getVersionName();

}

VersionServiceFactory.java

package com.gluonhq.charm.down.plugins;

import com.gluonhq.charm.down.DefaultServiceFactory;

public class VersionServiceFactory extends DefaultServiceFactory<VersionService> {

    public VersionServiceFactory() {
        super(VersionService.class);
    }

}

Android 包,位于 src/android/java 下:

AndroidVersionService.java

package com.gluonhq.charm.down.plugins.android;

import android.content.pm.PackageManager;
import com.gluonhq.charm.down.plugins.VersionService;
import javafxports.android.FXActivity;

public class AndroidVersionService implements VersionService {

    @Override
    public String getVersionName() {
        try {
            return FXActivity.getInstance().getPackageManager()
                    .getPackageInfo(FXActivity.getInstance().getPackageName(), 0)
                    .versionName;
        } catch (PackageManager.NameNotFoundException ex) { }
        return "";
    }

}

IOS包,位于src/ios/java下:

IOSVersionService.java

package com.gluonhq.charm.down.plugins.ios;

import com.gluonhq.charm.down.plugins.VersionService;

public class IOSVersionService implements VersionService {

    static {
        System.loadLibrary("Version");
    }

    @Override
    public String getVersionName() {
        return getNativeVersion();
    }

    private static native String getNativeVersion();

}

src/ios/native下:

版本.m

#import <UIKit/UIKit.h>
#include "jni.h"

JNIEXPORT jint JNICALL
JNI_OnLoad_Version(JavaVM *vm, void *reserved)
{
#ifdef JNI_VERSION_1_8
    //min. returned JNI_VERSION required by JDK8 for builtin libraries
    JNIEnv *env;
    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
        return JNI_VERSION_1_4;
    }
    return JNI_VERSION_1_8;
#else
    return JNI_VERSION_1_4;
#endif
}

JNIEXPORT jstring JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSVersionService_getNativeVersion
(JNIEnv *env, jclass jClass)
{
    NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    return (*env)->NewStringUTF(env, [version cStringUsingEncoding:NSASCIIStringEncoding]);
}

在根级别构建文件:

ios-build.gradle

if (System.getProperty('os.name').toLowerCase().contains("mac")) {
    new ByteArrayOutputStream().withStream { os ->
        exec {
            args '-version', '-sdk', 'iphoneos', 'SDKVersion'
            executable 'xcodebuild'
            standardOutput = os
        }
        ext.IOS_VERSION = os.toString().trim()
    }
} else {
    ext.IOS_VERSION = ""
}
ext.IS_DEBUG_NATIVE = Boolean.parseBoolean(System.getProperty("IS_DEBUG_NATIVE", "false"))

def sdkPath(String platform) {
    return "/Applications/Xcode.app/Contents/Developer/Platforms/${platform}.platform/Developer/SDKs/${platform}${IOS_VERSION}.sdk";
}

ext.xcodebuildIOS = {buildDir, projectDir, name ->

    if (!file(sdkPath('iPhoneOS')).exists()) {
        println "Skipping xcodebuild"
        return
    }

    // define statics do being able to configure the input/output files on the task
    // for faster builds if nothing changed
    def buildSystems = ["iPhoneOS+arm64",
                        "iPhoneOS+armv7",
                        "iPhoneSimulator+i386",
                        "iPhoneSimulator+x86_64"]
    def linkerOutputs = []

    def lipoOutput = "$buildDir/native/lib${name}.a"

    def nativeSources = ["$projectDir/src/ios/native/${name}.m"]

    // the actual task action
    buildSystems.each { buildSystem ->

        def (platform, arch) = buildSystem.tokenize("+");

        def compileOutput = "$buildDir/native/$arch"
        def compileOutputs = ["$buildDir/native/$arch/${name}.o"]

        def linkerOutput = "$buildDir/native/$arch/lib${name}.a"

        new File(compileOutput).mkdirs();

        def clangArgs = [
                "-x", "objective-c",
                "-miphoneos-version-min=6.0",
                "-fmessage-length=0",
                "-std=c99",
                "-fno-common",
                "-Wall",
                "-fno-strict-aliasing",
                "-fwrapv",
                "-fpascal-strings",
                "-fobjc-abi-version=2",
                "-fobjc-legacy-dispatch",
                "-I" + System.getenv("JAVA_HOME") + "/include",
                "-I" + System.getenv("JAVA_HOME") + "/include/darwin",
                "-c",
                IS_DEBUG_NATIVE ? ["-O0", "-DDEBUG", "-g"] : ["-O3", "-DNDEBUG"],
                "-arch", arch,
                "-isysroot",
                sdkPath(platform),
                nativeSources].flatten()
        // "-o", compileOutput,

        def linkerArgs = [
                "-static",
                "-framework", "Foundation",
                "-framework", "CoreGraphics",
                "-framework", "CoreBluetooth",
                "-framework", "CoreLocation",
                "-framework", "CoreMotion",
                "-framework", "CoreText",
                "-framework", "UIKit",
                "-framework", "QuartzCore",
                "-framework", "OpenGLES",
                "-framework", "UserNotifications",
                "-arch_only", arch,
                "-syslibroot", sdkPath(platform),
                "-L${sdkPath(platform)}/usr/lib",
                "-o", linkerOutput,
                compileOutputs
        ].flatten()

        // execute compiler
        exec {
            executable "clang"
            args clangArgs
            workingDir compileOutput
        }

        // execute linker
        exec {
            executable "libtool"
            args linkerArgs
            workingDir compileOutput
        }

        linkerOutputs.add(linkerOutput)
    }

    def lipoArgs = [
            "-create",
            linkerOutputs,
            "-o",
            lipoOutput
    ].flatten();

    // execute lipo to combine all linker output in one archive
    exec {
        executable "lipo"
        args lipoArgs
    }
}

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.3.16'
    }
}

apply plugin: 'org.javafxports.jfxmobile'
apply from: 'ios-build.gradle'

repositories {
    jcenter()
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
    }
}

mainClassName = 'your.main.class'

dependencies {
    compile 'com.gluonhq:charm:5.0.2'
}

jfxmobile {
    javafxportsVersion = '8.60.11'
    downConfig {
        version = '3.8.6'
        // Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
        plugins 'display', 'lifecycle', 'statusbar', 'storage'
    }
    android {
        manifest = 'src/android/AndroidManifest.xml'
    }
    ios {
        infoPList = file('src/ios/Default-Info.plist')
        forceLinkClasses = [
                'com.gluonhq.**.*',
                'javax.annotations.**.*',
                'javax.inject.**.*',
                'javax.json.**.*',
                'org.glassfish.json.**.*'
        ]
    }
}

task xcodebuild {
    doLast {
        xcodebuildIOS("$project.buildDir","$project.projectDir", "Version")
    }
}

task installNativeLib (type:Copy, dependsOn: xcodebuild) {
    from("$project.buildDir/native")
    into("src/ios/jniLibs")
    include("*.a")
}

在部署到 iOS 之前,运行:

./gradlew installNativeLib

服务使用

最后,您可以在代码中的任何位置使用该服务:

String version = Services.get(VersionService.class)
            .map(VersionService::getVersionName)
            .orElse(""));

关于javafx - 如何定义gluon应用程序版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56267716/

相关文章:

android - 为什么 iOS 版本的 Gluon Mobile 应用程序的大小是 Android 相同应用程序版本的 10 倍?

JavaFX TableView 编辑整数单元格

java - 在 NetBeans 中向 JavaFXPorts 项目添加单元测试 - Retrolambda 的问题

android - Javafxports 和 Gluon 魅力 - 如何在不将 Android 连接到 PC 的情况下生成 apk

intellij-idea - 如何让 JavaFX 和 Java 11 在 IntelliJ IDEA 中工作

java - 关于android文件管理、Android环境概念和android库插件

JavaFX 去除工具栏渐变

JavaFx:如何使用 scenebuilder 制作可点击的图像

scrollbar - javafx TableView 中的垂直滚动条不起作用

ios - Gluon Mobile VideoService 在后台无法在 iphone 上运行