简体   繁体   English

libGDX / RoboVM项目中的MFMailComposeViewController生成错误

[英]Build error with MFMailComposeViewController in a libGDX / RoboVM project

I'm trying to add functionality to an existing iOS libGDX app (using RoboVM) so that when a scene2d.ui button is pressed, an MFMailComposeViewController popup is displayed with a predefined set of CSV files attached that are stored in the app's Library > local folder. 我正在尝试向现有的iOS libGDX应用程序添加功能(使用RoboVM),以便在按scene2d.ui按钮时,显示MFMailComposeViewController弹出窗口,并附带一组预定义的CSV文件,这些文件存储在应用程序的“库”>“本地”中夹。 Here's the code I have so far: 这是我到目前为止的代码:

Imports & members: 进口和会员:

import org.robovm.apple.foundation.*;
import org.robovm.apple.messageui.MFMailComposeResult;
import org.robovm.apple.messageui.MFMailComposeViewController;
import org.robovm.apple.messageui.MFMailComposeViewControllerDelegate;
import org.robovm.apple.uikit.*;
import org.robovm.objc.ObjCObject;

private UIWindow mailWindow;
private UIViewController mailViewController;
private MFMailComposeViewController mailPicker;

Methods: 方法:

private void createMailWindow() 
{
    mailWindow = new UIWindow(UIScreen.getMainScreen().getBounds());
    mailViewController = new UIViewController();
    mailWindow.setRootViewController(mailViewController);
}

private void sendEmail(String fileName, String subject, String body) 
{
    mailPicker = new MFMailComposeViewController();
    mailPicker.addStrongRef(mailWindow);
    String path = NSBundle.getMainBundle().getResourcePath();

    if (fileName != null)
    {
        path = path.substring(0, path.lastIndexOf('/')) + "/Library/local/" + fileName;
    }

        MFMailComposeViewControllerDelegate delegate = new MFMailComposeViewControllerDelegate()
        {
            public void mailComposeControllerDidFinish(MFMailComposeViewController controller, MFMailComposeResult result, NSError error) 
            {
                controller.dismissViewController(true, null);
                mailPicker.removeFromParentViewController();
                mailPicker.removeStrongRef(mailWindow);
                mailWindow.setHidden(true);
                mailPicker = null;
            }

            @Override
            public void didFinish(MFMailComposeViewController controller, MFMailComposeResult result, NSError error) 
            {

            }
        };

        mailPicker.setMailComposeDelegate(delegate);
        mailPicker.addStrongRef((ObjCObject) delegate);

        if (fileName != null)
        {
                // attach CSVs here...
        }

        mailPicker.setSubject((subject != null ? subject : "Test Results"));
        mailPicker.setMessageBody((body != null ? body : "Please find attached the latest results data."), false);

        if (MFMailComposeViewController.canSendMail())
        {
            mailWindow.getRootViewController().presentViewController(mailPicker, true, null);
            mailWindow.makeKeyAndVisible();
        }
    }
}

I have this code in place and Eclipse doesn't flag any problems until I attempt a build, whereby I get the following error: 我已经准备好了这段代码,并且在尝试构建之前,Eclipse不会标记任何问题,因此会出现以下错误:

Exception in thread "main" java.lang.NoClassDefFoundError: org/robovm/rt/bro/NativeObject
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at com.mmu.cfa.DesktopMain.main(DesktopMain.java:26)
Caused by: java.lang.ClassNotFoundException: org.robovm.rt.bro.NativeObject
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 49 more

I've added the RoboVM Cocoa Touch Library and the RoboVM Runtime Library to my main project's build path. 我已将RoboVM Cocoa Touch库和RoboVM运行时库添加到我的主项目的构建路径中。 If I remove these two methods, my project builds without error. 如果删除这两种方法,则项目构建不会出错。 Is there something else I need to setup to get this running? 我还需要设置其他东西才能使它运行吗?

Problem 问题

In a Libgdx application, the main project is shared by the projects of all supported platforms. 在Libgdx应用程序中, 主项目由所有受支持平台的项目共享

So main project must contain platform independent code . 因此, 主项目必须包含平台无关的代码

RoboVM Cocoa Touch Library and RoboVM Runtime Library are platform dependent and would work only on iOS and not on desktop, android, html etc. RoboVM Cocoa Touch LibraryRoboVM Runtime Library依赖于平台,仅在iOS上有效,而不能在台式机,android,html等上使用。


Solution

  1. Remove RoboVM Cocoa Touch Library and RoboVM Runtime Library dependencies from main project. 从主项目中删除RoboVM Cocoa Touch库RoboVM运行时库依赖项。
  2. Add those dependencies to the RoboVM project. 将那些依赖项添加到RoboVM项目。 (If they are not already present.) (如果尚不存在。)
  3. Create an interface representing the functionality that you require in the main project . 创建一个代表您在主项目中所需功能的接口

     public interface EmailHandler { public void createMailWindow(); public void sendEmail(String fileName, String subject, String body); } 
  4. Create an implementation class in the robovm project with the code you have already written. 使用您已经编写的代码在robovm项目中创建一个实现类

     public class RobovmEmailHandler implements EmailHandler { @Override public void createMailWindow() { // Your code goes here. } @Override public void sendEmail(String fileName, String subject, String body) { // Your code goes here. } } 
  5. Add the EmailHandler parameter to the constructor of ApplicationListener (your main game class in main project). EmailHandler 参数添加 ApplicationListener (您在主项目中的主要游戏类的构造函数中。

     public class MyAwesomeGame extends Game { private EmailHandler emailHandler; // Use it wherever you like. public MyAwesomeGame(EmailHandler emailHandler) { this.emailHandler = emailHandler; // Rest of constructor. } } 
  6. Supply the implementation argument in RobovmLauncher (main class of robovm project). 供应在执行参数 RobovmLauncher (主类robovm项目)。

     public class RobovmLauncher extends IOSApplication.Delegate { @Override protected IOSApplication createApplication() { EmailHandler emailHandler = new RobovmEmailHandler(); IOSApplicationConfiguration config = new IOSApplicationConfiguration(); return new IOSApplication(new MyAwesomeGame(emailHandler), config); } } 

Note: 注意:
Projects of other platforms would start shouting at you to provide an EmailHandler to them. 其他平台的项目将开始向您喊叫,以向他们提供EmailHandler This is natural and expected. 这是自然而然的。 You should provide platform specific implementation of the interface for each platform you want to target. 您应该为要定位的每个平台提供特定于平台的接口实现。

Hope this helps. 希望这可以帮助。
Good luck. 祝好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM