nickromano / MacAPIsInCatalyst

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MacAPIsInCatalyst

Demo of running an AppKit bundle from a Catalyst app. Following the guides found here High Caffeine Content and here Crunchy Bagel.

1. Add a macOS bundle

2. Link it to the main app

3. Create a new Objective-C class in the bundle

This class will access the macOS only APIs

MacBundle.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MacBundle : NSObject

+ (NSDictionary *)runShell:(NSArray<NSString *> *)arguments workingDirectory:(NSURL *)workingDir;

@end

NS_ASSUME_NONNULL_END

MacBundle.m

#import "MacBundle.h"

@implementation MacBundle

+ (NSDictionary *)runShell:(NSArray<NSString *> *)arguments workingDirectory:(NSURL *)workingDir {
  NSTask *task = [[NSTask alloc] init];
  task.launchPath = @"/usr/bin/env";

  [task setCurrentDirectoryPath:workingDir.path];

  NSPipe * output = [NSPipe pipe];
  [task setStandardOutput:output];

  task.arguments = arguments;
  [task launch];
  [task waitUntilExit];

  NSFileHandle * read = [output fileHandleForReading];
  NSData * dataRead = [read readDataToEndOfFile];
  NSString * stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];

  return @{
    @"output": stringRead,
    @"code": @(task.terminationStatus)
  };
}

@end

4. Set the name of this class in your bundle's Info.plist for the key "Principal Class"

5. Call this code from the main app target

#if targetEnvironment(macCatalyst)
let pluginPath = (Bundle.main.builtInPlugInsURL?.appendingPathComponent("MacBundle.bundle").path)!
let bundle = Bundle(path: pluginPath)!
bundle.load()

// Load the principal class from the bundle
// This is set in MacBundle/Info.plist
let principalClass = bundle.principalClass as AnyObject as! NSObjectProtocol

let workingDir = FileManager.default.temporaryDirectory

// Add an example file for "ls" to return below
try! "testing".write(to: workingDir.appendingPathComponent("test.txt"), atomically: true, encoding: .utf8)

let selector = NSSelectorFromString("runShell:workingDirectory:")
let result = principalClass.perform(selector, with: ["ls"], with: workingDir)!.takeUnretainedValue() as! [String: Any]
let code = result["code"] as! Int
let output = result["output"] as! String
print(code, output)
#endif

About


Languages

Language:Swift 80.1%Language:Objective-C 19.9%