[ Solved ] [ iOS ] How to open a custom file extension using "Open in MyApp" ?



  • I have a Qt 5.5 widget app.

    After adding UTExportedTypeDeclarations and CFBundleDocumentTypes sections to my Info.plist, I can now open a file attachment in Apple Mail and select "Open in MyApp" then MyApp launches.

    How can I receive the file and open it? Has anyone figured this out?

    I see openURL and didFinishLaunchingWithOptions being discussed.

    • (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
      {
      // handle the URL here
      }

    The LaunchMe Example uses OpenURL.
    https://developer.apple.com/library/ios/samplecode/LaunchMe/Introduction/Intro.html

    How to do same in Qt seems challenging.

    Thanks in advance for any tips,

    -Ed



  • Ben Lau on Qt Interest mailing list explained that Objective-C categories can be used to override classes even if you do not have the header file.

    I do not understand how. The following somehow works without having to initialize it to the instance of UIApplication.

    I put a breakpoint in openURL. When I open an email attachment, my app is launched, and the breakpoint is hit. Magic.

    File: myappdelegate.mm

    #include <UIKit/UIKit.h>

    #include "qiosapplicationdelegate.h"

    #include "mainwindow.h"

    @implementation QIOSApplicationDelegate (CmsApplicationDelegate)

    • (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
      sourceApplication:(NSString *)sourceApplication
      annotation:(id)annotation
      {
      Q_UNUSED(application);
      Q_UNUSED(annotation);

      NSLog(@"sourceApplication: %@",sourceApplication);
      NSLog(@"url: %@",url);

      // A bit of ugly code involving adding a static instance method and a static variable
      // But it works!
      //
      cms::MainWindow* mainWindow = cms::MainWindow::instance();
      if(0 != mainWindow)
      {
      QString filePath = QString::fromNSString(url.path);
      qDebug("filePath %s", filePath.toLatin1().data());
      mainWindow->openFile(filePath);
      }

      return YES;
      }
      @end

    I added an INCLUDEPATH to my project file.

    File: myapp.pro

    ios {
    QTBASE=$$clean_path($$QMAKE_QMAKE/../../..)/Src/qtbase
    INCLUDEPATH += $$QTBASE/src/plugins/platforms/ios
    }

    -Ed



  • This post is deleted!


  • I found a solution I like better that posts a QFileOpenEvent.

    I like it better because in order to handle file open on OS X I had to subclass QApplication and give it a pointer to my MainWindow to handle the QFileOpenEvent. Now my OS X and iOS implementation are similar and easier to maintain.

    File: cmsapplication.h

    <pre>
    #include <UIKit/UIKit.h>

    #include <QDebug>
    #include <QFileOpenEvent>

    #include "qiosapplicationdelegate.h"

    /// \category QIOSApplicationDelegate(CmsApplicationDelegate)
    /// \abstract A category on QIOSApplicationDelegate to override openURL

    /// Use the Objective-C category feature to override the openURL method
    @implementation QIOSApplicationDelegate (CmsApplicationDelegate)

    /// Posts a QFileOpenEvent to QCoreApplication when iOS calls openURL.
    ///
    /// This allows userto open a TSR file from Apple Mail,
    /// select "Open in TSR", to launch TSR and pass openURL the
    /// file to open.
    ///
    /// Must add UTExportedTypeDeclarations and CFBundleDocumentTypes to your
    /// Info.plist for this to work.
    ///
    /// Example: Info.plist
    /// \verbatim
    /// <key>UTExportedTypeDeclarations</key>
    /// <array>
    /// <dict>
    /// <key>UTTypeConformsTo</key>
    /// <array>
    /// <string>public.data</string>
    /// </array>
    /// <key>UTTypeDescription</key>
    /// <string>Tracking Status Report</string>
    /// <key>UTTypeIdentifier</key>
    /// <string>com.ditchwitch.tsr</string>
    /// <key>UTTypeTagSpecification</key>
    /// <dict>
    /// <key>public.filename-extension</key>
    /// <string>tsr</string>
    /// <key>public.mime-type</key>
    /// <string>public.data</string>
    /// </dict>
    /// </dict>
    /// </array>
    /// <key>CFBundleDocumentTypes</key>
    /// <array>
    /// <dict>
    /// <key>CFBundleTypeIconFiles</key>
    /// <array>
    /// <string>Icon.png</string>
    /// </array>
    /// <key>CFBundleTypeName</key>
    /// <string>Tracking Status Report</string>
    /// <key>CFBundleTypeRole</key>
    /// <string>Editor</string>
    /// <key>LSHandlerRank</key>
    /// <string>Owner</string>
    /// <key>LSItemContentTypes</key>
    /// <array>
    /// <string>com.ditchwitch.tsr</string>
    /// <string>public.data</string>
    /// </array>
    /// </dict>
    /// </array>
    /// \endverbatim
    ///
    /// See file: cmsapplication.cpp
    /// \see cmsapplication.cpp
    ///
    /// \see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html
    ///

    • (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
      sourceApplication:(NSString *)sourceApplication
      annotation:(id)annotation
      {
      Q_UNUSED(application);
      Q_UNUSED(annotation);

      NSLog(@"sourceApplication: %@",sourceApplication);
      NSLog(@"url: %@",url);

      QString filePath = QString::fromNSString(url.path);
      qDebug("filePath %s", filePath.toLatin1().data());

      QFileOpenEvent *fileOpenEvent = new QFileOpenEvent(filePath);
      QCoreApplication::postEvent(QCoreApplication::instance(), fileOpenEvent);

      return YES;
      }

    @end
    </pre>

    File: cmsapplication.cpp

    // class CmsApplication : public QApplication

    <pre>
    #if defined(Q_OS_OSX) || defined(Q_OS_IOS)
    // Looks for QFileOpenEvent to implement TSR file open from
    /// other apps, for example, Finder on OS X, or Apple Mail on iOS and OS X.
    ///
    ///
    /// \remarks Could this work on Android too?
    ///
    /// See file: cmsapplicationdelegate.mm
    /// \see cmsapplicationdelegate.mm
    ///
    bool CmsApplication::event(QEvent* event)
    {
    qDebug() << event->type();
    // iOS receives ApplicationDeactivate, ApllicationStateChange, when Home is pressed
    // When iOS user opens Mail file attachment using "Open in TSR", ApplicationActivate event received but NOT QEvent::FileOpen
    switch (event->type())
    {
    case QEvent::ApplicationActivate:
    {
    //clean();
    if (false == m_mainWindow.isMinimized())
    {
    m_mainWindow.show();
    }
    return true;
    }
    case QEvent::FileOpen:
    {
    QString fileName = static_cast<QFileOpenEvent *>(event)->file();
    m_mainWindow.openFile(fileName);
    return true;
    }
    default:
    break;
    }
    return QApplication::event(event);
    }
    #endif
    </pre>


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.