From ed0ebc576650853ec91238600347cf5a9a84a9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Sun, 25 Feb 2024 16:40:34 +0700 Subject: [PATCH 1/2] refactor: move to Swift --- .gitignore | 5 + Classes/TiCaptureSession.h | 28 - Classes/TiCaptureSession.m | 92 --- Classes/TiCaptureSession.swift | 91 +++ Classes/TiCoreml.h | 16 + Classes/TiCoremlModule.h | 14 - Classes/TiCoremlModule.m | 42 -- Classes/TiCoremlModule.swift | 24 + Classes/TiCoremlModuleAssets.h | 9 +- Classes/TiCoremlModuleAssets.m | 12 +- Classes/TiCoremlRealtimeRecognitionView.h | 13 - Classes/TiCoremlRealtimeRecognitionView.m | 18 - Classes/TiCoremlRealtimeRecognitionView.swift | 21 + .../TiCoremlRealtimeRecognitionViewProxy.h | 38 -- .../TiCoremlRealtimeRecognitionViewProxy.m | 133 ---- ...TiCoremlRealtimeRecognitionViewProxy.swift | 118 ++++ Info.plist | 24 + TiCoreml_Prefix.pch | 9 +- hooks/ti.swiftsupport.js | 39 ++ manifest | 13 +- module.xcconfig | 24 +- platform/README.md | 11 + timodule.xml | 6 +- titanium-coreml.xcodeproj/project.pbxproj | 588 +++++++++--------- .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + titanium.xcconfig | 14 +- 27 files changed, 700 insertions(+), 717 deletions(-) create mode 100644 .gitignore delete mode 100644 Classes/TiCaptureSession.h delete mode 100644 Classes/TiCaptureSession.m create mode 100644 Classes/TiCaptureSession.swift create mode 100644 Classes/TiCoreml.h delete mode 100644 Classes/TiCoremlModule.h delete mode 100644 Classes/TiCoremlModule.m create mode 100644 Classes/TiCoremlModule.swift delete mode 100644 Classes/TiCoremlRealtimeRecognitionView.h delete mode 100644 Classes/TiCoremlRealtimeRecognitionView.m create mode 100644 Classes/TiCoremlRealtimeRecognitionView.swift delete mode 100644 Classes/TiCoremlRealtimeRecognitionViewProxy.h delete mode 100644 Classes/TiCoremlRealtimeRecognitionViewProxy.m create mode 100644 Classes/TiCoremlRealtimeRecognitionViewProxy.swift create mode 100644 Info.plist create mode 100644 hooks/ti.swiftsupport.js create mode 100644 platform/README.md create mode 100644 titanium-coreml.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 titanium-coreml.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5886e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +dist +.DS_Store +titanium-coreml.xcodeproj/project.xcworkspace/xcuserdata/*.xcuserdatad +titanium-coreml.xcodeproj/xcuserdata/*.xcuserdatad diff --git a/Classes/TiCaptureSession.h b/Classes/TiCaptureSession.h deleted file mode 100644 index 63e8d45..0000000 --- a/Classes/TiCaptureSession.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// TiCaptureSession.h -// titanium-coreml -// -// Created by Hans Knöchel on 05.07.17. -// - -#import -#import - -typedef void(^TiCaptureSessionCompletionHandler)(CVImageBufferRef sampleBuffer); - -@interface TiCaptureSession : NSObject { - TiCaptureSessionCompletionHandler _completionHandler; -} - -- (instancetype)initWithCompletionHandler:(TiCaptureSessionCompletionHandler)completionHandler; - -- (void)start; - -- (void)stop; - -@property(nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; -@property(nonatomic, strong) AVCaptureSession *captureSession; -@property(nonatomic, strong) AVCaptureVideoDataOutput *videoOutput; -@property(nonatomic, strong) dispatch_queue_t queue; - -@end diff --git a/Classes/TiCaptureSession.m b/Classes/TiCaptureSession.m deleted file mode 100644 index 2b45808..0000000 --- a/Classes/TiCaptureSession.m +++ /dev/null @@ -1,92 +0,0 @@ -// -// TiCaptureSession.m -// titanium-coreml -// -// Created by Hans Knöchel on 05.07.17. -// - -#import "TiCaptureSession.h" -#import "TiApp.h" - -@implementation TiCaptureSession - -- (instancetype)initWithCompletionHandler:(TiCaptureSessionCompletionHandler)completionHandler -{ - if (self = [super init]) { - _completionHandler = completionHandler; - _queue = dispatch_queue_create("com.axway.ti.coreml.camera-queue", NULL); - [self setupCaptureSession]; - } - - return self; -} - -- (void)setupCaptureSession -{ - _captureSession = [[AVCaptureSession alloc] init]; - _videoOutput = [[AVCaptureVideoDataOutput alloc] init]; - - [[self captureSession] beginConfiguration]; - - [[self captureSession] setSessionPreset:AVCaptureSessionPresetPhoto]; - - AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - NSError *videoInputError = nil; - - if (captureDevice == nil) { - NSLog(@"Error: Could not create capture device"); - } - - AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&videoInputError]; - - if (videoInputError != nil) { - NSLog(@"Error: Could not create video input"); - } - - if ([self.captureSession canAddInput:videoInput]) { - [[self captureSession] addInput:videoInput]; - } else { - NSLog(@"Error: Cannot add video input to capture session"); - } - - _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; - _previewLayer.videoGravity = AVLayerVideoGravityResizeAspect; - _previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait; - - NSDictionary *settings = @{ - (id)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] - }; - - _videoOutput.videoSettings = settings; - _videoOutput.alwaysDiscardsLateVideoFrames = YES; - [_videoOutput setSampleBufferDelegate:self queue:_queue]; - - if ([[self captureSession] canAddOutput:_videoOutput]) { - [[self captureSession] addOutput:_videoOutput]; - } else { - NSLog(@"Error: Cannot add video output to capture session"); - } - - [_videoOutput connectionWithMediaType:AVMediaTypeVideo]; - - [self.captureSession commitConfiguration]; -} - -- (void)start -{ - [[self captureSession] startRunning]; -} - -- (void)stop -{ - [[self captureSession] stopRunning]; -} - -// MARK: AVCaptureVideoDataOutputSampleBufferDelegate - -- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection -{ - _completionHandler(CMSampleBufferGetImageBuffer(sampleBuffer)); -} - -@end diff --git a/Classes/TiCaptureSession.swift b/Classes/TiCaptureSession.swift new file mode 100644 index 0000000..2406809 --- /dev/null +++ b/Classes/TiCaptureSession.swift @@ -0,0 +1,91 @@ +// +// TiCaptureSession.swift +// TiCoreml +// +// Created by Hans Knöchel on 25.02.24. +// + +import UIKit +import AVFoundation +import CoreVideo + +typealias TiCaptureSessionCompletionHandler = (CVImageBuffer) -> Void + +class TiCaptureSession: NSObject { + + let queue = DispatchQueue(label: "io.tidev.coreml.camera-queue") + let completionHandler: TiCaptureSessionCompletionHandler + let captureSession = AVCaptureSession() + let videoOutput = AVCaptureVideoDataOutput() + + var previewLayer: AVCaptureVideoPreviewLayer! + + init(completionHandler: @escaping TiCaptureSessionCompletionHandler) { + self.completionHandler = completionHandler + + super.init() + + self.setupCaptureSession() + } + + private func setupCaptureSession() { + captureSession.beginConfiguration() + captureSession.sessionPreset = .photo + + guard let captureDevice = AVCaptureDevice.default(for: .video) else { + fatalError("Could not create capture device") + } + + guard let videoInput = try? AVCaptureDeviceInput(device: captureDevice) else { + fatalError("Could not create video input") + } + + guard captureSession.canAddInput(videoInput) else { + fatalError("Could not add video input to capture session") + } + + captureSession.addInput(videoInput) + + previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) + previewLayer.videoGravity = .resizeAspect + + if #available(iOS 17.0, *) { + previewLayer.connection?.videoRotationAngle = 90 + } else { + previewLayer.connection?.videoOrientation = .portrait + } + + videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] + videoOutput.alwaysDiscardsLateVideoFrames = true + videoOutput.setSampleBufferDelegate(self, queue: queue) + + + guard captureSession.canAddOutput(videoOutput) else { + fatalError("Could not add video output to capture session") + } + + captureSession.addOutput(videoOutput) + + let _ = videoOutput.connection(with: .video) + captureSession.commitConfiguration() + } + + func start() { + captureSession.startRunning() + } + + func stop() { + captureSession.stopRunning() + } +} + +// MARK: AVCaptureVideoDataOutputSampleBufferDelegate + +extension TiCaptureSession: AVCaptureVideoDataOutputSampleBufferDelegate { + + func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { + if let image = CMSampleBufferGetImageBuffer(sampleBuffer) { + completionHandler(image) + } + } +} diff --git a/Classes/TiCoreml.h b/Classes/TiCoreml.h new file mode 100644 index 0000000..05ee30e --- /dev/null +++ b/Classes/TiCoreml.h @@ -0,0 +1,16 @@ +// +// TiCoreml.h +// titanium-coreml +// +// Created by Hans Knöchel on 25.02.24. +// + +#import + +//! Project version number for TiCoreml. +FOUNDATION_EXPORT double TiCoremlVersionNumber; + +//! Project version string for TiCoreml. +FOUNDATION_EXPORT const unsigned char TiCoremlVersionString[]; + +#import diff --git a/Classes/TiCoremlModule.h b/Classes/TiCoremlModule.h deleted file mode 100644 index d3c8831..0000000 --- a/Classes/TiCoremlModule.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * titanium-coreml - * - * Created by Hans Knoechel - * Copyright (c) 2017 Your Company. All rights reserved. - */ - -#import "TiModule.h" - -@interface TiCoremlModule : TiModule -{ -} - -@end diff --git a/Classes/TiCoremlModule.m b/Classes/TiCoremlModule.m deleted file mode 100644 index 424f397..0000000 --- a/Classes/TiCoremlModule.m +++ /dev/null @@ -1,42 +0,0 @@ -/** - * titanium-coreml - * - * Created by Hans Knoechel - * Copyright (c) 2017 Axway Appcelerator. All rights reserved. - */ - -#import "TiCoremlModule.h" -#import "TiBase.h" -#import "TiHost.h" -#import "TiUtils.h" - -@implementation TiCoremlModule - -#pragma mark Internal - -- (id)moduleGUID -{ - return @"ab74a8a3-fce2-4042-8463-2049e4bdc961"; -} - -- (NSString *)moduleId -{ - return @"ti.coreml"; -} - -#pragma mark Lifecycle - -- (void)startup -{ - [super startup]; - NSLog(@"[DEBUG] %@ loaded",self); -} - -#pragma Public APIs - -- (id)isSupported:(id)unused -{ - return NUMBOOL([TiUtils isIOSVersionOrGreater:@"11.0"]); -} - -@end diff --git a/Classes/TiCoremlModule.swift b/Classes/TiCoremlModule.swift new file mode 100644 index 0000000..43a0e33 --- /dev/null +++ b/Classes/TiCoremlModule.swift @@ -0,0 +1,24 @@ +// +// TiCoremlModule.swift +// titanium-coreml +// +// Created by Your Name +// Copyright (c) 2024 Your Company. All rights reserved. +// + +import UIKit +import TitaniumKit + +@objc(TiCoremlModule) +class TiCoremlModule: TiModule { + + @objc public let isSupported = true + + func moduleGUID() -> String { + return "eb79624b-04d4-463c-9f43-d212de1b53e3" + } + + override func moduleId() -> String! { + return "ti.coreml" + } +} diff --git a/Classes/TiCoremlModuleAssets.h b/Classes/TiCoremlModuleAssets.h index f29845a..7f56742 100644 --- a/Classes/TiCoremlModuleAssets.h +++ b/Classes/TiCoremlModuleAssets.h @@ -2,10 +2,11 @@ * This is a generated file. Do not edit or your changes will be lost */ -@interface TiCoremlModuleAssets : NSObject -{ +@interface TiCoremlModuleAssets : NSObject { + } -- (NSData*) moduleAsset; -- (NSData*) resolveModuleAsset:(NSString*)path; + +- (NSData *)moduleAsset; +- (NSData *)resolveModuleAsset:(NSString*)path; @end diff --git a/Classes/TiCoremlModuleAssets.m b/Classes/TiCoremlModuleAssets.m index b8180e6..8bce54b 100644 --- a/Classes/TiCoremlModuleAssets.m +++ b/Classes/TiCoremlModuleAssets.m @@ -7,18 +7,18 @@ @implementation TiCoremlModuleAssets -- (NSData*) moduleAsset +- (NSData *)moduleAsset { - + - return nil; + return nil; } -- (NSData*) resolveModuleAsset:(NSString*)path +- (NSData *)resolveModuleAsset:(NSString *)path { - + - return nil; + return nil; } @end diff --git a/Classes/TiCoremlRealtimeRecognitionView.h b/Classes/TiCoremlRealtimeRecognitionView.h deleted file mode 100644 index e45bebe..0000000 --- a/Classes/TiCoremlRealtimeRecognitionView.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Appcelerator Titanium Mobile - * Copyright (c) 2009-2017 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the Apache Public License - * Please see the LICENSE included with this distribution for details. - */ -#import "TiUIView.h" - -@interface TiCoremlRealtimeRecognitionView : TiUIView { - -} - -@end diff --git a/Classes/TiCoremlRealtimeRecognitionView.m b/Classes/TiCoremlRealtimeRecognitionView.m deleted file mode 100644 index fcb2410..0000000 --- a/Classes/TiCoremlRealtimeRecognitionView.m +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Appcelerator Titanium Mobile - * Copyright (c) 2009-2017 by Appcelerator, Inc. All Rights Reserved. - * Licensed under the terms of the Apache Public License - * Please see the LICENSE included with this distribution for details. - */ - -#import "TiCoremlRealtimeRecognitionView.h" -#import "TiCoremlRealtimeRecognitionViewProxy.h" - -@implementation TiCoremlRealtimeRecognitionView - -- (void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds -{ - [(TiCoremlRealtimeRecognitionViewProxy *)[self proxy] adjustFrame]; -} - -@end diff --git a/Classes/TiCoremlRealtimeRecognitionView.swift b/Classes/TiCoremlRealtimeRecognitionView.swift new file mode 100644 index 0000000..b6b53c9 --- /dev/null +++ b/Classes/TiCoremlRealtimeRecognitionView.swift @@ -0,0 +1,21 @@ +// +// TiCoremlRealtimeRecognitionView.swift +// TiCoreml +// +// Created by Hans Knöchel on 25.02.24. +// + +import CoreVideo +import TitaniumKit +import UIKit + +class TiCoremlRealtimeRecognitionView: TiUIView { + + override func frameSizeChanged(_ frame: CGRect, bounds: CGRect) { + super.frameSizeChanged(frame, bounds: bounds) + + if let proxy = proxy as? TiCoremlRealtimeRecognitionViewProxy { + proxy.adjustFrame() + } + } +} diff --git a/Classes/TiCoremlRealtimeRecognitionViewProxy.h b/Classes/TiCoremlRealtimeRecognitionViewProxy.h deleted file mode 100644 index 978747a..0000000 --- a/Classes/TiCoremlRealtimeRecognitionViewProxy.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// TiCoremlRealtimeRecognitionProxy.h -// titanium-coreml -// -// Created by Hans Knöchel on 05.07.17. -// - -#if IS_IOS_11 - -#import "TiViewProxy.h" -#import "TiCaptureSession.h" - -#import -#import - -@interface TiCoremlRealtimeRecognitionViewProxy : TiViewProxy { - @private - TiCaptureSession *_captureSession; - UIView *_previewView; - VNCoreMLRequest *_request; - CVImageBufferRef _currentSampleBuffer; -} - -- (void)adjustFrame; - -#pragma mark Public API's - -- (void)startRecognition:(id)unused; - -- (void)stopRecognition:(id)unused; - -- (id)isRecognizing:(id)unused; - -- (void)takePicture:(id)value; - -@end - -#endif diff --git a/Classes/TiCoremlRealtimeRecognitionViewProxy.m b/Classes/TiCoremlRealtimeRecognitionViewProxy.m deleted file mode 100644 index b8f41ad..0000000 --- a/Classes/TiCoremlRealtimeRecognitionViewProxy.m +++ /dev/null @@ -1,133 +0,0 @@ -// -// TiCoremlRealtimeRecognitionProxy.m -// titanium-coreml -// -// Created by Hans Knöchel on 05.07.17. -// - -#if IS_IOS_11 - -#import "TiCoremlRealtimeRecognitionViewProxy.h" -#import "TiUtils.h" - -@implementation TiCoremlRealtimeRecognitionViewProxy - -#pragma mark Internal - -- (TiCaptureSession *)captureSession -{ - if (_captureSession == nil) { - _captureSession = [[TiCaptureSession alloc] initWithCompletionHandler:^(CVImageBufferRef sampleBuffer) { - _currentSampleBuffer = sampleBuffer; - [self processRecognitionWithSampleBuffer:sampleBuffer]; - }]; - - AVCaptureVideoPreviewLayer *previewLayer = [_captureSession previewLayer]; - - [[[self view] layer] addSublayer:previewLayer]; - [self adjustFrame]; - } - - return _captureSession; -} - -- (void)adjustFrame -{ - [_captureSession previewLayer].frame = [self view].bounds; -} - -- (VNCoreMLRequest *)request -{ - if (_request == nil) { - // Setup CoreML model - NSError *visionModelError = nil; - NSError *modelError = nil; - MLModel *model = [MLModel modelWithContentsOfURL:[TiUtils toURL:[self valueForKey:@"model"] proxy:self] - error:&modelError]; - - if (modelError != nil) { - [self throwException:@"Error creating model" subreason:[modelError localizedDescription] location:CODELOCATION]; - } - - // Setup Vision CoreML model - VNCoreMLModel *visionModel = [VNCoreMLModel modelForMLModel:model - error:&visionModelError]; - - if (visionModelError != nil) { - [self throwException:@"Error creating vision model" subreason:[visionModelError localizedDescription] location:CODELOCATION]; - } - - // Setup Vision CoreML request - _request = [[VNCoreMLRequest alloc] initWithModel:visionModel completionHandler:^(VNRequest *request, NSError *error) { - NSArray *observations = [request results]; - - NSMutableArray *> *result = [NSMutableArray arrayWithCapacity:[observations count]]; - - for (VNClassificationObservation *observation in observations) { - [result addObject:@{ - @"identifier": observation.identifier, - @"confidence": NUMFLOAT(observation.confidence), - }]; - } - TiThreadPerformOnMainThread(^{ - [self fireEvent:@"classification" withObject:@{@"classifications": result}]; - }, NO); - }]; - - _request.imageCropAndScaleOption = VNImageCropAndScaleOptionCenterCrop; - } - - return _request; -} - -- (void)processRecognitionWithSampleBuffer:(CVImageBufferRef)sampleBuffer -{ - NSError *handlerError = nil; - VNImageRequestHandler *handler = [[VNImageRequestHandler alloc] initWithCVPixelBuffer:sampleBuffer options:@{}]; - - [handler performRequests:@[[self request]] error:&handlerError]; - - if (handlerError != nil) { - NSLog([NSString stringWithFormat:@"[ERROR] Error processing buffer: %@", [handlerError localizedDescription]]); - } -} - -#pragma mark Public API's - -- (void)startRecognition:(id)unused -{ - if (![[[self captureSession] captureSession] isRunning]) { - [[self captureSession] start]; - } else { - NSLog(@"[ERROR] Trying to start a capture session that is already running!"); - } -} - -- (void)stopRecognition:(id)unused -{ - if ([[[self captureSession] captureSession] isRunning]) { - [[self captureSession] stop]; - } else { - NSLog(@"[ERROR] Trying to stop a capture session that is not running!"); - } -} - -- (id)isRecognizing:(id)unused -{ - return NUMBOOL([[[self captureSession] captureSession] isRunning]); -} - -- (void)takePicture:(id)value -{ - ENSURE_SINGLE_ARG(value, KrollCallback); - - CIImage *ciImage = [CIImage imageWithCVPixelBuffer:_currentSampleBuffer]; - CIContext *context = [CIContext contextWithOptions:nil]; - CGImageRef image = [context createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(_currentSampleBuffer), CVPixelBufferGetHeight(_currentSampleBuffer))]; - - [(KrollCallback*)value call:@[@{@"image": [[TiBlob alloc] initWithImage:[UIImage imageWithCGImage:image]]}] thisObject:self]; -} - -@end - -#endif diff --git a/Classes/TiCoremlRealtimeRecognitionViewProxy.swift b/Classes/TiCoremlRealtimeRecognitionViewProxy.swift new file mode 100644 index 0000000..99e945b --- /dev/null +++ b/Classes/TiCoremlRealtimeRecognitionViewProxy.swift @@ -0,0 +1,118 @@ +// +// TiCoremlRealtimeRecognitionViewProxy.swift +// TiCoreml +// +// Created by Hans Knöchel on 25.02.24. +// + +import CoreVideo +import TitaniumKit +import UIKit +import Vision + +class TiCoremlRealtimeRecognitionViewProxy: TiViewProxy { + + private var currentSampleBuffer: CVImageBuffer? + private var previewView: UIView? + lazy private var request: VNCoreMLRequest = { + guard let model = try? MLModel(contentsOf: TiUtils.toURL(self.value(forKey: "model") as? String, proxy: self)) else { + fatalError("Error creating model") + } + + guard let visionModel = try? VNCoreMLModel(for: model) else { + fatalError("Error creating vision model") + + } + + let _request = VNCoreMLRequest(model: visionModel) { request, error in + guard let observations = request.results else { + return + } + + let result: [[String: Any]] = observations.map { + [ + "identifier": $0.uuid, + "confidence": $0.confidence + ] + } + + DispatchQueue.main.async { + self.fireEvent("classification", with: ["classifications": result]) + } + } + + _request.imageCropAndScaleOption = .centerCrop; + + return _request; + }() + + lazy private var captureSession: TiCaptureSession = { + let session = TiCaptureSession(completionHandler: { imageBuffer in + self.currentSampleBuffer = imageBuffer + self.processRecognitionWithSampleBuffer() + }) + + self.view.layer.addSublayer(session.previewLayer) + self.adjustFrame() + + return session + }() + + func adjustFrame() { + captureSession.previewLayer.frame = view.bounds; + } + + private func processRecognitionWithSampleBuffer() { + guard let sampleBuffer = currentSampleBuffer else { return } + let handler = VNImageRequestHandler(cvPixelBuffer: sampleBuffer) + + do { + try handler.perform([request]) + } catch { + fatalError("Error processing buffer: \(error.localizedDescription)") + } + } +} + +// MARK: Public APIs + +extension TiCoremlRealtimeRecognitionViewProxy { + + @objc func startRecognition(unused: Any?) { + if captureSession.captureSession.isRunning { + NSLog("[ERROR] Trying to start a capture session that is already running!") + return + } + + captureSession.start() + } + + @objc func stopRecognition(unused: Any?) { + if !captureSession.captureSession.isRunning { + NSLog("[ERROR] Trying to stop a capture session that is not running!"); + return + } + + captureSession.stop() + } + + @objc func isRecognizing(unused: Any?) -> Bool { + return captureSession.captureSession.isRunning + } + + @objc func takePicture(value: [Any]) { + guard let sampleBuffer = currentSampleBuffer, + let calback = value.first as? KrollCallback else { + return + } + + let ciImage = CIImage(cvPixelBuffer: sampleBuffer) + let context = CIContext() + + guard let image = context.createCGImage(ciImage, from: CGRect(x: 0, y: 0, width: CVPixelBufferGetWidth(sampleBuffer), height: CVPixelBufferGetHeight(sampleBuffer))) else { + return + } + + calback.call([["image": TiBlob(image: UIImage(cgImage: image))]], thisObject: self) + } +} diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..fbe1e6b --- /dev/null +++ b/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/TiCoreml_Prefix.pch b/TiCoreml_Prefix.pch index d83dd47..2fb3c7f 100644 --- a/TiCoreml_Prefix.pch +++ b/TiCoreml_Prefix.pch @@ -1,12 +1,5 @@ #ifdef __OBJC__ #import - #import -#endif - -// iOS 11+ API's -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 - #define IS_IOS_11 true -#else - #define IS_IOS_11 false #endif + diff --git a/hooks/ti.swiftsupport.js b/hooks/ti.swiftsupport.js new file mode 100644 index 0000000..9994003 --- /dev/null +++ b/hooks/ti.swiftsupport.js @@ -0,0 +1,39 @@ +/** + * Ti.SwiftSupport + * Copyright (c) 2018-present by Axway Appcelerator. + * All Rights Reserved. + */ + +'use strict'; + +exports.id = 'ti.swiftsupport'; +exports.cliVersion = '>=3.2'; +exports.init = init; + +/** + * Main entry point for our plugin which looks for the platform specific + * plugin to invoke. + * + * @param {Object} logger The logger instance. + * @param {Object} config The hook config. + * @param {Object} cli The Titanium CLI instance. + * @param {Object} appc The Appcelerator CLI instance. + */ +// eslint-disable-next-line no-unused-vars +function init(logger, config, cli, appc) { + cli.on('build.ios.xcodeproject', { + pre: function (data) { + var xobjs = data.args[0].hash.project.objects; + + Object.keys(xobjs.PBXNativeTarget).forEach(function (targetUuid) { + var target = xobjs.PBXNativeTarget[targetUuid]; + if (target && typeof target === 'object') { + xobjs.XCConfigurationList[target.buildConfigurationList].buildConfigurations.forEach(function (buildConf) { + var buildSettings = xobjs.XCBuildConfiguration[buildConf.value].buildSettings; + buildSettings.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = 'YES'; + }); + } + }); + } + }); +} diff --git a/manifest b/manifest index 8c51f7b..b51cb6f 100644 --- a/manifest +++ b/manifest @@ -2,17 +2,18 @@ # this is your module manifest and used by Titanium # during compilation, packaging, distribution, etc. # -version: 1.0.1 +version: 2.0.0 apiversion: 2 -architectures: armv7 arm64 i386 x86_64 +architectures: arm64 x86_64 +mac: false description: titanium-coreml -author: Hans Knoechel +author: Hans Knöchel license: Apache 2 -copyright: Copyright (c) 2017 by Axway Appcelerator +copyright: Copyright (c) 2018-present by Hans Knöchel # these should not be edited name: titanium-coreml moduleid: ti.coreml -guid: f39ef2bb-26ef-409b-aad4-c9e70b1016b5 +guid: eb79624b-04d4-463c-9f43-d212de1b53e3 platform: iphone -minsdk: 6.2.0 +minsdk: 12.0.0 diff --git a/module.xcconfig b/module.xcconfig index 9d95ef0..3423d99 100644 --- a/module.xcconfig +++ b/module.xcconfig @@ -4,9 +4,25 @@ // // see the following webpage for instructions on the settings // for this file: -// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeBuildSystem/400-Build_Configurations/build_configs.html +// https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Build_Settings.html // -OTHER_LDFLAGS[sdk=iphoneos11*]=$(inherited) -framework CoreML -OTHER_LDFLAGS[sdk=iphonesimulator11*]=$(inherited) -framework CoreML - +// +// How to manually add a Framework (example) +// Note: Titanium SDK 6.2.2+ detects and links frameworks automatically +// +// OTHER_LDFLAGS=$(inherited) -framework Foo +// +// Adding a framework for a specific version(s) of iOS, e.g iOS 11: +// +// OTHER_LDFLAGS[sdk=iphoneos11*]=$(inherited) -framework Foo +// OTHER_LDFLAGS[sdk=iphonesimulator11*]=$(inherited) -framework Foo +// +// +// How to add a compiler define: +// +// OTHER_CFLAGS=$(inherited) -DFOO=1 +// +// +// IMPORTANT NOTE: always use $(inherited) in your overrides +// diff --git a/platform/README.md b/platform/README.md new file mode 100644 index 0000000..04e952f --- /dev/null +++ b/platform/README.md @@ -0,0 +1,11 @@ +Files in this folder are copied directory into the iOS build directory +when the iOS app is compiled: + + /build/iphone + +You can place files such as asset catalog files, .framework files and storyboards in this +directory. + +Files in this directory are copied directly on top of whatever files are already +in the build directory, so please be careful that your files don't clobber +essential project files or files from other modules. diff --git a/timodule.xml b/timodule.xml index 6affb2f..a8b700a 100644 --- a/timodule.xml +++ b/timodule.xml @@ -1,13 +1,11 @@ - + - - diff --git a/titanium-coreml.xcodeproj/project.pbxproj b/titanium-coreml.xcodeproj/project.pbxproj index 9c09771..6c53abf 100644 --- a/titanium-coreml.xcodeproj/project.pbxproj +++ b/titanium-coreml.xcodeproj/project.pbxproj @@ -3,487 +3,481 @@ archiveVersion = 1; classes = { }; - objectVersion = 48; + objectVersion = 54; objects = { -/* Begin PBXAggregateTarget section */ - 24416B8111C4CA220047AFDD /* Build & Test */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */; - buildPhases = ( - 24416B8011C4CA220047AFDD /* ShellScript */, - ); - dependencies = ( - 24416B8511C4CA280047AFDD /* PBXTargetDependency */, - ); - name = "Build & Test"; - productName = "Build & test"; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ - 24DD6CF91134B3F500162E58 /* TiCoremlModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DD6CF71134B3F500162E58 /* TiCoremlModule.h */; }; - 24DD6CFA1134B3F500162E58 /* TiCoremlModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DD6CF81134B3F500162E58 /* TiCoremlModule.m */; }; - 24DE9E1111C5FE74003F90F6 /* TiCoremlModuleAssets.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DE9E0F11C5FE74003F90F6 /* TiCoremlModuleAssets.h */; }; - 24DE9E1211C5FE74003F90F6 /* TiCoremlModuleAssets.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DE9E1011C5FE74003F90F6 /* TiCoremlModuleAssets.m */; }; - AA747D9F0F9514B9006C5449 /* TiCoreml_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* TiCoreml_Prefix.pch */; }; - AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; - DB8AA2BA1F0DD7920011DF6F /* TiCaptureSession.h in Headers */ = {isa = PBXBuildFile; fileRef = DBD7DB081F0DCF270080BCC9 /* TiCaptureSession.h */; }; - DB8AA2BB1F0DD7920011DF6F /* TiCoremlRealtimeRecognitionViewProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = DBD7DB071F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.h */; }; - DB8AA2BC1F0DD79A0011DF6F /* TiCaptureSession.m in Sources */ = {isa = PBXBuildFile; fileRef = DBD7DB091F0DCF270080BCC9 /* TiCaptureSession.m */; }; - DB8AA2BD1F0DD79A0011DF6F /* TiCoremlRealtimeRecognitionViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = DBD7DB061F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.m */; }; - DBD7DB041F0DAE720080BCC9 /* CoreML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBD7DB031F0DAE6B0080BCC9 /* CoreML.framework */; }; - DBF1F31E1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.h in Headers */ = {isa = PBXBuildFile; fileRef = DBF1F31C1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.h */; }; - DBF1F31F1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.m in Sources */ = {isa = PBXBuildFile; fileRef = DBF1F31D1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.m */; }; + 3A4802AB2B8B025000F0C3DF /* CoreML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4802AA2B8B025000F0C3DF /* CoreML.framework */; }; + 3A4802AF2B8B02C700F0C3DF /* TiCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4802AE2B8B02C700F0C3DF /* TiCaptureSession.swift */; }; + 3A4802B12B8B02E000F0C3DF /* TiCoremlRealtimeRecognitionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4802B02B8B02E000F0C3DF /* TiCoremlRealtimeRecognitionView.swift */; }; + 3A4802B32B8B02F100F0C3DF /* TiCoremlRealtimeRecognitionViewProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4802B22B8B02F100F0C3DF /* TiCoremlRealtimeRecognitionViewProxy.swift */; }; + 3A4802B52B8B408200F0C3DF /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4802B42B8B408200F0C3DF /* CoreVideo.framework */; }; + 3A4802B72B8B408800F0C3DF /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A4802B62B8B408800F0C3DF /* Vision.framework */; }; + B1E00E65241D179500C384C1 /* TitaniumKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1E00E64241D179500C384C1 /* TitaniumKit.xcframework */; }; + DB34CDE0207B998A005F8E8C /* TiCoremlModuleAssets.m in Sources */ = {isa = PBXBuildFile; fileRef = DB34CDDE207B998A005F8E8C /* TiCoremlModuleAssets.m */; }; + DB34CDE1207B998A005F8E8C /* TiCoremlModuleAssets.h in Headers */ = {isa = PBXBuildFile; fileRef = DB34CDDF207B998A005F8E8C /* TiCoremlModuleAssets.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DB34CDE6207B9EBD005F8E8C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB34CDE5207B9EBD005F8E8C /* Foundation.framework */; }; + DB52E2401E9CCF8D00AAAEE0 /* TiCoreml_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = DB52E23F1E9CCF8D00AAAEE0 /* TiCoreml_Prefix.pch */; }; + DB52E2431E9CD0F800AAAEE0 /* TiCoremlModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB52E2421E9CD0F800AAAEE0 /* TiCoremlModule.swift */; }; + DB75E5161E9CD59000809B2D /* TiCoreml.h in Headers */ = {isa = PBXBuildFile; fileRef = DB75E5151E9CD58100809B2D /* TiCoreml.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = D2AAC07D0554694100DB518D; - remoteInfo = "titanium-coreml"; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ - 24DD6CF71134B3F500162E58 /* TiCoremlModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TiCoremlModule.h; path = Classes/TiCoremlModule.h; sourceTree = ""; }; - 24DD6CF81134B3F500162E58 /* TiCoremlModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TiCoremlModule.m; path = Classes/TiCoremlModule.m; sourceTree = ""; }; - 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; - 24DE9E0F11C5FE74003F90F6 /* TiCoremlModuleAssets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TiCoremlModuleAssets.h; path = Classes/TiCoremlModuleAssets.h; sourceTree = ""; }; - 24DE9E1011C5FE74003F90F6 /* TiCoremlModuleAssets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TiCoremlModuleAssets.m; path = Classes/TiCoremlModuleAssets.m; sourceTree = ""; }; - AA747D9E0F9514B9006C5449 /* TiCoreml_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiCoreml_Prefix.pch; sourceTree = SOURCE_ROOT; }; - AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - D2AAC07E0554694100DB518D /* libti.coreml.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libti.coreml.a; sourceTree = BUILT_PRODUCTS_DIR; }; - DBD7DB031F0DAE6B0080BCC9 /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = System/Library/Frameworks/CoreML.framework; sourceTree = SDKROOT; }; - DBD7DB051F0DAE8E0080BCC9 /* Vision.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vision.framework; path = System/Library/Frameworks/Vision.framework; sourceTree = SDKROOT; }; - DBD7DB061F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TiCoremlRealtimeRecognitionViewProxy.m; path = Classes/TiCoremlRealtimeRecognitionViewProxy.m; sourceTree = ""; }; - DBD7DB071F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TiCoremlRealtimeRecognitionViewProxy.h; path = Classes/TiCoremlRealtimeRecognitionViewProxy.h; sourceTree = ""; }; - DBD7DB081F0DCF270080BCC9 /* TiCaptureSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TiCaptureSession.h; path = Classes/TiCaptureSession.h; sourceTree = ""; }; - DBD7DB091F0DCF270080BCC9 /* TiCaptureSession.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TiCaptureSession.m; path = Classes/TiCaptureSession.m; sourceTree = ""; }; - DBF1F31C1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TiCoremlRealtimeRecognitionView.h; path = Classes/TiCoremlRealtimeRecognitionView.h; sourceTree = ""; }; - DBF1F31D1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TiCoremlRealtimeRecognitionView.m; path = Classes/TiCoremlRealtimeRecognitionView.m; sourceTree = ""; }; + 3A4802AA2B8B025000F0C3DF /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/System/Library/Frameworks/CoreML.framework; sourceTree = DEVELOPER_DIR; }; + 3A4802AE2B8B02C700F0C3DF /* TiCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TiCaptureSession.swift; path = Classes/TiCaptureSession.swift; sourceTree = ""; }; + 3A4802B02B8B02E000F0C3DF /* TiCoremlRealtimeRecognitionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TiCoremlRealtimeRecognitionView.swift; path = Classes/TiCoremlRealtimeRecognitionView.swift; sourceTree = ""; }; + 3A4802B22B8B02F100F0C3DF /* TiCoremlRealtimeRecognitionViewProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TiCoremlRealtimeRecognitionViewProxy.swift; path = Classes/TiCoremlRealtimeRecognitionViewProxy.swift; sourceTree = ""; }; + 3A4802B42B8B408200F0C3DF /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/System/Library/Frameworks/CoreVideo.framework; sourceTree = DEVELOPER_DIR; }; + 3A4802B62B8B408800F0C3DF /* Vision.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vision.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/System/Library/Frameworks/Vision.framework; sourceTree = DEVELOPER_DIR; }; + B1E00E64241D179500C384C1 /* TitaniumKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TitaniumKit.xcframework; path = "$(TITANIUM_SDK)/iphone/Frameworks/TitaniumKit.xcframework"; sourceTree = ""; }; + DB34CDDE207B998A005F8E8C /* TiCoremlModuleAssets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TiCoremlModuleAssets.m; path = Classes/TiCoremlModuleAssets.m; sourceTree = SOURCE_ROOT; }; + DB34CDDF207B998A005F8E8C /* TiCoremlModuleAssets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TiCoremlModuleAssets.h; path = Classes/TiCoremlModuleAssets.h; sourceTree = SOURCE_ROOT; }; + DB34CDE5207B9EBD005F8E8C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + DB52E22A1E9CCD7000AAAEE0 /* TiCoreml.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TiCoreml.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DB52E22E1E9CCD7000AAAEE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + DB52E23F1E9CCF8D00AAAEE0 /* TiCoreml_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiCoreml_Prefix.pch; sourceTree = SOURCE_ROOT; }; + DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; + DB52E2421E9CD0F800AAAEE0 /* TiCoremlModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TiCoremlModule.swift; path = Classes/TiCoremlModule.swift; sourceTree = ""; }; + DB75E5151E9CD58100809B2D /* TiCoreml.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TiCoreml.h; path = Classes/TiCoreml.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - D2AAC07C0554694100DB518D /* Frameworks */ = { + DB52E2261E9CCD7000AAAEE0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DBD7DB041F0DAE720080BCC9 /* CoreML.framework in Frameworks */, - AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, + DB34CDE6207B9EBD005F8E8C /* Foundation.framework in Frameworks */, + B1E00E65241D179500C384C1 /* TitaniumKit.xcframework in Frameworks */, + 3A4802AB2B8B025000F0C3DF /* CoreML.framework in Frameworks */, + 3A4802B72B8B408800F0C3DF /* Vision.framework in Frameworks */, + 3A4802B52B8B408200F0C3DF /* CoreVideo.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 034768DFFF38A50411DB9C8B /* Products */ = { + DB258CA41F0964DE000D0D8D /* Misc */ = { isa = PBXGroup; children = ( - D2AAC07E0554694100DB518D /* libti.coreml.a */, + DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */, + DB34CDDF207B998A005F8E8C /* TiCoremlModuleAssets.h */, + DB34CDDE207B998A005F8E8C /* TiCoremlModuleAssets.m */, + DB75E5151E9CD58100809B2D /* TiCoreml.h */, + DB52E23F1E9CCF8D00AAAEE0 /* TiCoreml_Prefix.pch */, + DB52E22E1E9CCD7000AAAEE0 /* Info.plist */, ); - name = Products; + name = Misc; sourceTree = ""; }; - 0867D691FE84028FC02AAC07 /* titanium-coreml */ = { + DB258CA51F0964F6000D0D8D /* Sources */ = { isa = PBXGroup; children = ( - 08FB77AEFE84172EC02AAC07 /* Classes */, - 32C88DFF0371C24200C91783 /* Other Sources */, - 0867D69AFE84028FC02AAC07 /* Frameworks */, - 034768DFFF38A50411DB9C8B /* Products */, + DB52E2421E9CD0F800AAAEE0 /* TiCoremlModule.swift */, + 3A4802AE2B8B02C700F0C3DF /* TiCaptureSession.swift */, + 3A4802B02B8B02E000F0C3DF /* TiCoremlRealtimeRecognitionView.swift */, + 3A4802B22B8B02F100F0C3DF /* TiCoremlRealtimeRecognitionViewProxy.swift */, ); - name = "titanium-coreml"; + name = Sources; sourceTree = ""; }; - 0867D69AFE84028FC02AAC07 /* Frameworks */ = { + DB34CDE2207B9D6A005F8E8C /* Frameworks */ = { isa = PBXGroup; children = ( - DBD7DB051F0DAE8E0080BCC9 /* Vision.framework */, - DBD7DB031F0DAE6B0080BCC9 /* CoreML.framework */, - AACBBE490F95108600F1A2B1 /* Foundation.framework */, + 3A4802B62B8B408800F0C3DF /* Vision.framework */, + 3A4802B42B8B408200F0C3DF /* CoreVideo.framework */, + 3A4802AA2B8B025000F0C3DF /* CoreML.framework */, + B1E00E64241D179500C384C1 /* TitaniumKit.xcframework */, + DB34CDE5207B9EBD005F8E8C /* Foundation.framework */, ); name = Frameworks; sourceTree = ""; }; - 08FB77AEFE84172EC02AAC07 /* Classes */ = { + DB52E2201E9CCD7000AAAEE0 = { + isa = PBXGroup; + children = ( + DB52E22C1E9CCD7000AAAEE0 /* TiCoreml */, + DB52E22B1E9CCD7000AAAEE0 /* Products */, + DB34CDE2207B9D6A005F8E8C /* Frameworks */, + ); + sourceTree = ""; + }; + DB52E22B1E9CCD7000AAAEE0 /* Products */ = { isa = PBXGroup; children = ( - 24DE9E0F11C5FE74003F90F6 /* TiCoremlModuleAssets.h */, - 24DE9E1011C5FE74003F90F6 /* TiCoremlModuleAssets.m */, - 24DD6CF71134B3F500162E58 /* TiCoremlModule.h */, - 24DD6CF81134B3F500162E58 /* TiCoremlModule.m */, - DBD7DB081F0DCF270080BCC9 /* TiCaptureSession.h */, - DBD7DB091F0DCF270080BCC9 /* TiCaptureSession.m */, - DBF1F31C1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.h */, - DBF1F31D1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.m */, - DBD7DB071F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.h */, - DBD7DB061F0DCF270080BCC9 /* TiCoremlRealtimeRecognitionViewProxy.m */, + DB52E22A1E9CCD7000AAAEE0 /* TiCoreml.framework */, ); - name = Classes; + name = Products; sourceTree = ""; }; - 32C88DFF0371C24200C91783 /* Other Sources */ = { + DB52E22C1E9CCD7000AAAEE0 /* TiCoreml */ = { isa = PBXGroup; children = ( - AA747D9E0F9514B9006C5449 /* TiCoreml_Prefix.pch */, - 24DD6D1B1134B66800162E58 /* titanium.xcconfig */, + DB258CA51F0964F6000D0D8D /* Sources */, + DB258CA41F0964DE000D0D8D /* Misc */, ); - name = "Other Sources"; + name = TiCoreml; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - D2AAC07A0554694100DB518D /* Headers */ = { + DB52E2271E9CCD7000AAAEE0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - DB8AA2BA1F0DD7920011DF6F /* TiCaptureSession.h in Headers */, - DBF1F31E1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.h in Headers */, - DB8AA2BB1F0DD7920011DF6F /* TiCoremlRealtimeRecognitionViewProxy.h in Headers */, - AA747D9F0F9514B9006C5449 /* TiCoreml_Prefix.pch in Headers */, - 24DD6CF91134B3F500162E58 /* TiCoremlModule.h in Headers */, - 24DE9E1111C5FE74003F90F6 /* TiCoremlModuleAssets.h in Headers */, + DB75E5161E9CD59000809B2D /* TiCoreml.h in Headers */, + DB34CDE1207B998A005F8E8C /* TiCoremlModuleAssets.h in Headers */, + DB52E2401E9CCF8D00AAAEE0 /* TiCoreml_Prefix.pch in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - D2AAC07D0554694100DB518D /* titanium-coreml */ = { + DB52E2291E9CCD7000AAAEE0 /* TiCoreml */ = { isa = PBXNativeTarget; - buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "titanium-coreml" */; + buildConfigurationList = DB52E2321E9CCD7000AAAEE0 /* Build configuration list for PBXNativeTarget "TiCoreml" */; buildPhases = ( - D2AAC07A0554694100DB518D /* Headers */, - D2AAC07B0554694100DB518D /* Sources */, - D2AAC07C0554694100DB518D /* Frameworks */, + DB52E2251E9CCD7000AAAEE0 /* Sources */, + DB52E2261E9CCD7000AAAEE0 /* Frameworks */, + DB52E2271E9CCD7000AAAEE0 /* Headers */, + DB52E2281E9CCD7000AAAEE0 /* Resources */, ); buildRules = ( ); dependencies = ( + DBB66220208481A400EAD6D9 /* PBXTargetDependency */, ); - name = "titanium-coreml"; - productName = "titanium-coreml"; - productReference = D2AAC07E0554694100DB518D /* libti.coreml.a */; - productType = "com.apple.product-type.library.static"; + name = TiCoreml; + productName = TiCoreml; + productReference = DB52E22A1E9CCD7000AAAEE0 /* TiCoreml.framework */; + productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 0867D690FE84028FC02AAC07 /* Project object */ = { + DB52E2211E9CCD7000AAAEE0 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + TargetAttributes = { + DB52E2291E9CCD7000AAAEE0 = { + CreatedOnToolsVersion = 8.3; + LastSwiftMigration = 0940; + ProvisioningStyle = Automatic; + }; + }; }; - buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "titanium-coreml" */; - compatibilityVersion = "Xcode 8.0"; - developmentRegion = English; - hasScannedForEncodings = 1; + buildConfigurationList = DB52E2241E9CCD7000AAAEE0 /* Build configuration list for PBXProject "titanium-coreml" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; knownRegions = ( - English, - Japanese, - French, - German, + en, + Base, ); - mainGroup = 0867D691FE84028FC02AAC07 /* titanium-coreml */; - productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + mainGroup = DB52E2201E9CCD7000AAAEE0; + productRefGroup = DB52E22B1E9CCD7000AAAEE0 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - D2AAC07D0554694100DB518D /* titanium-coreml */, - 24416B8111C4CA220047AFDD /* Build & Test */, + DB52E2291E9CCD7000AAAEE0 /* TiCoreml */, ); }; /* End PBXProject section */ -/* Begin PBXShellScriptBuildPhase section */ - 24416B8011C4CA220047AFDD /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; +/* Begin PBXResourcesBuildPhase section */ + DB52E2281E9CCD7000AAAEE0 /* Resources */ = { + isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# shell script goes here\n\npython \"${TITANIUM_SDK}/titanium.py\" run --dir=\"${PROJECT_DIR}\"\nexit $?\n"; }; -/* End PBXShellScriptBuildPhase section */ +/* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - D2AAC07B0554694100DB518D /* Sources */ = { + DB52E2251E9CCD7000AAAEE0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DB8AA2BC1F0DD79A0011DF6F /* TiCaptureSession.m in Sources */, - DB8AA2BD1F0DD79A0011DF6F /* TiCoremlRealtimeRecognitionViewProxy.m in Sources */, - DBF1F31F1F0E9391000D0100 /* TiCoremlRealtimeRecognitionView.m in Sources */, - 24DD6CFA1134B3F500162E58 /* TiCoremlModule.m in Sources */, - 24DE9E1211C5FE74003F90F6 /* TiCoremlModuleAssets.m in Sources */, + 3A4802B12B8B02E000F0C3DF /* TiCoremlRealtimeRecognitionView.swift in Sources */, + DB34CDE0207B998A005F8E8C /* TiCoremlModuleAssets.m in Sources */, + 3A4802B32B8B02F100F0C3DF /* TiCoremlRealtimeRecognitionViewProxy.swift in Sources */, + 3A4802AF2B8B02C700F0C3DF /* TiCaptureSession.swift in Sources */, + DB52E2431E9CD0F800AAAEE0 /* TiCoremlModule.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 24416B8511C4CA280047AFDD /* PBXTargetDependency */ = { + DBB66220208481A400EAD6D9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = D2AAC07D0554694100DB518D /* titanium-coreml */; - targetProxy = 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */; + name = TitaniumKit; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 1DEB921F08733DC00010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; - buildSettings = { - CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DSTROOT = /tmp/TiCoreml.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; - GCC_WARN_ABOUT_RETURN_TYPE = NO; - GCC_WARN_MISSING_PARENTHESES = NO; - GCC_WARN_SHADOW = NO; - GCC_WARN_STRICT_SELECTOR_MATCH = NO; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_PARAMETER = NO; - GCC_WARN_UNUSED_VALUE = NO; - GCC_WARN_UNUSED_VARIABLE = NO; - INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = ( - "-DDEBUG", - "-DTI_POST_1_2", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = ti.coreml; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - RUN_CLANG_STATIC_ANALYZER = NO; - SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = ""; - WARNING_CFLAGS = "-Wno-arc-performSelector-leaks"; - }; - name = Debug; - }; - 1DEB922008733DC00010E9CD /* Release */ = { + DB52E2301E9CCD7000AAAEE0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + baseConfigurationReference = DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; - DSTROOT = /tmp/TiCoreml.dst; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; - GCC_WARN_ABOUT_RETURN_TYPE = NO; - GCC_WARN_MISSING_PARENTHESES = NO; - GCC_WARN_SHADOW = NO; - GCC_WARN_STRICT_SELECTOR_MATCH = NO; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_PARAMETER = NO; - GCC_WARN_UNUSED_VALUE = NO; - GCC_WARN_UNUSED_VARIABLE = NO; - INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = "-DTI_POST_1_2"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = ti.coreml; - RUN_CLANG_STATIC_ANALYZER = NO; - SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = ""; - WARNING_CFLAGS = "-Wno-arc-performSelector-leaks"; - }; - name = Release; - }; - 1DEB922308733DC00010E9CD /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; - buildSettings = { - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LIBRARY = "compiler-default"; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DSTROOT = /tmp/TiCoreml.dst; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = c99; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = NO; - GCC_WARN_MISSING_PARENTHESES = NO; - GCC_WARN_SHADOW = NO; - GCC_WARN_STRICT_SELECTOR_MATCH = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_PARAMETER = NO; - GCC_WARN_UNUSED_VALUE = NO; - GCC_WARN_UNUSED_VARIABLE = NO; - INSTALL_PATH = /usr/local/lib; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; + MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ( - "-DDEBUG", - "-DTI_POST_1_2", - ); - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = ti.coreml; - PROVISIONING_PROFILE = ""; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - RUN_CLANG_STATIC_ANALYZER = NO; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = ""; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 1DEB922408733DC00010E9CD /* Release */ = { + DB52E2311E9CCD7000AAAEE0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + baseConfigurationReference = DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LIBRARY = "compiler-default"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - DSTROOT = /tmp/TiCoreml.dst; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_MODEL_TUNING = G5; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; - GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; - GCC_TREAT_WARNINGS_AS_ERRORS = NO; - GCC_VERSION = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = NO; - GCC_WARN_MISSING_PARENTHESES = NO; - GCC_WARN_SHADOW = NO; - GCC_WARN_STRICT_SELECTOR_MATCH = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_PARAMETER = NO; - GCC_WARN_UNUSED_VALUE = NO; - GCC_WARN_UNUSED_VARIABLE = NO; - INSTALL_PATH = /usr/local/lib; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - OTHER_CFLAGS = "-DTI_POST_1_2"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = ti.coreml; - RUN_CLANG_STATIC_ANALYZER = NO; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; + MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = ""; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALID_ARCHS = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Release; }; - 24416B8211C4CA220047AFDD /* Debug */ = { + DB52E2331E9CCD7000AAAEE0 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + baseConfigurationReference = DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */; buildSettings = { - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - PRODUCT_NAME = "Build & test"; + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ""; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; + OTHER_CFLAGS = ( + "-DDEBUG", + "-DTI_POST_1_2", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.appcelerator.titanium-coreml"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Titanium"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Debug; }; - 24416B8311C4CA220047AFDD /* Release */ = { + DB52E2341E9CCD7000AAAEE0 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + baseConfigurationReference = DB52E2411E9CD09900AAAEE0 /* titanium.xcconfig */; buildSettings = { - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - PRODUCT_NAME = "Build & test"; - ZERO_LINK = NO; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Manual; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = ""; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = TiCoreml_Prefix.pch; + GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ""; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; + OTHER_CFLAGS = "-DTI_POST_1_2"; + OTHER_LDFLAGS = ( + "-ObjC", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.appcelerator.titanium-coreml"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_INCLUDE_PATHS = "$(SRCROOT)/Titanium"; + SWIFT_VERSION = 5.0; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "titanium-coreml" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1DEB921F08733DC00010E9CD /* Debug */, - 1DEB922008733DC00010E9CD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "titanium-coreml" */ = { + DB52E2241E9CCD7000AAAEE0 /* Build configuration list for PBXProject "titanium-coreml" */ = { isa = XCConfigurationList; buildConfigurations = ( - 1DEB922308733DC00010E9CD /* Debug */, - 1DEB922408733DC00010E9CD /* Release */, + DB52E2301E9CCD7000AAAEE0 /* Debug */, + DB52E2311E9CCD7000AAAEE0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */ = { + DB52E2321E9CCD7000AAAEE0 /* Build configuration list for PBXNativeTarget "TiCoreml" */ = { isa = XCConfigurationList; buildConfigurations = ( - 24416B8211C4CA220047AFDD /* Debug */, - 24416B8311C4CA220047AFDD /* Release */, + DB52E2331E9CCD7000AAAEE0 /* Debug */, + DB52E2341E9CCD7000AAAEE0 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = 0867D690FE84028FC02AAC07 /* Project object */; + rootObject = DB52E2211E9CCD7000AAAEE0 /* Project object */; } diff --git a/titanium-coreml.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/titanium-coreml.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/titanium-coreml.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/titanium-coreml.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/titanium-coreml.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/titanium-coreml.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/titanium.xcconfig b/titanium.xcconfig index 0852f78..ba84d10 100644 --- a/titanium.xcconfig +++ b/titanium.xcconfig @@ -4,17 +4,11 @@ // OF YOUR TITANIUM SDK YOU'RE BUILDING FOR // // -TITANIUM_SDK_VERSION = 6.1.1.GA - +TITANIUM_SDK_VERSION = 12.3.0.GA // // THESE SHOULD BE OK GENERALLY AS-IS // -TITANIUM_SDK = ~/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) -TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" -TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" -TITANIUM_BASE_SDK3 = "$(TITANIUM_SDK)/iphone/include/JavaScriptCore" -HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) $(TITANIUM_BASE_SDK3) - - - +TITANIUM_SDK = /Users/$(USER)/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) +HEADER_SEARCH_PATHS = $(inherited) "$(TITANIUM_SDK)/iphone/include" +FRAMEWORK_SEARCH_PATHS = $(inherited) "$(TITANIUM_SDK)/iphone/Frameworks/**" From 94127f5a66e3bdaeb76af530443a9cf098cd2106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans=20Kn=C3=B6chel?= Date: Wed, 28 Feb 2024 15:06:16 +0700 Subject: [PATCH 2/2] chore: fix remaining bugs, polish for production usage --- .gitignore | 1 + Classes/TiCaptureSession.swift | 19 +++-- Classes/TiCoremlModule.swift | 21 ++++- Classes/TiCoremlRealtimeRecognitionView.swift | 1 + ...TiCoremlRealtimeRecognitionViewProxy.swift | 78 ++++++++++++------- README.md | 47 +++-------- example/app.js | 69 +++++++++------- 7 files changed, 134 insertions(+), 102 deletions(-) diff --git a/.gitignore b/.gitignore index d5886e3..06f3141 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dist .DS_Store titanium-coreml.xcodeproj/project.xcworkspace/xcuserdata/*.xcuserdatad titanium-coreml.xcodeproj/xcuserdata/*.xcuserdatad +/test_coreml diff --git a/Classes/TiCaptureSession.swift b/Classes/TiCaptureSession.swift index 2406809..2ec6813 100644 --- a/Classes/TiCaptureSession.swift +++ b/Classes/TiCaptureSession.swift @@ -33,35 +33,34 @@ class TiCaptureSession: NSObject { captureSession.sessionPreset = .photo guard let captureDevice = AVCaptureDevice.default(for: .video) else { - fatalError("Could not create capture device") + return logErrorAndFail("Could not create capture device") } guard let videoInput = try? AVCaptureDeviceInput(device: captureDevice) else { - fatalError("Could not create video input") + return logErrorAndFail("Could not create video input") } guard captureSession.canAddInput(videoInput) else { - fatalError("Could not add video input to capture session") + return logErrorAndFail("Could not add video input to capture session") } captureSession.addInput(videoInput) previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.videoGravity = .resizeAspect - - if #available(iOS 17.0, *) { - previewLayer.connection?.videoRotationAngle = 90 - } else { + +// if #available(iOS 17.0, *) { +// previewLayer.connection?.videoRotationAngle = 90 +// } else { previewLayer.connection?.videoOrientation = .portrait - } +// } videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] videoOutput.alwaysDiscardsLateVideoFrames = true videoOutput.setSampleBufferDelegate(self, queue: queue) - guard captureSession.canAddOutput(videoOutput) else { - fatalError("Could not add video output to capture session") + return logErrorAndFail("Could not add video output to capture session") } captureSession.addOutput(videoOutput) diff --git a/Classes/TiCoremlModule.swift b/Classes/TiCoremlModule.swift index 43a0e33..48cd319 100644 --- a/Classes/TiCoremlModule.swift +++ b/Classes/TiCoremlModule.swift @@ -6,13 +6,17 @@ // Copyright (c) 2024 Your Company. All rights reserved. // +import AVFoundation import UIKit import TitaniumKit +func logErrorAndFail(_ message: String) { + NSLog("[ERROR] \(message)") + fatalError(message) +} + @objc(TiCoremlModule) class TiCoremlModule: TiModule { - - @objc public let isSupported = true func moduleGUID() -> String { return "eb79624b-04d4-463c-9f43-d212de1b53e3" @@ -21,4 +25,17 @@ class TiCoremlModule: TiModule { override func moduleId() -> String! { return "ti.coreml" } + + @objc(isSupported:) + func isSupported(unused: Any?) -> Bool { + guard let captureDevice = AVCaptureDevice.default(for: .video) else { + return false + } + + guard let _ = try? AVCaptureDeviceInput(device: captureDevice) else { + return false + } + + return true + } } diff --git a/Classes/TiCoremlRealtimeRecognitionView.swift b/Classes/TiCoremlRealtimeRecognitionView.swift index b6b53c9..c08c476 100644 --- a/Classes/TiCoremlRealtimeRecognitionView.swift +++ b/Classes/TiCoremlRealtimeRecognitionView.swift @@ -9,6 +9,7 @@ import CoreVideo import TitaniumKit import UIKit +@objc(TiCoremlRealtimeRecognitionView) class TiCoremlRealtimeRecognitionView: TiUIView { override func frameSizeChanged(_ frame: CGRect, bounds: CGRect) { diff --git a/Classes/TiCoremlRealtimeRecognitionViewProxy.swift b/Classes/TiCoremlRealtimeRecognitionViewProxy.swift index 99e945b..564bbfd 100644 --- a/Classes/TiCoremlRealtimeRecognitionViewProxy.swift +++ b/Classes/TiCoremlRealtimeRecognitionViewProxy.swift @@ -10,28 +10,44 @@ import TitaniumKit import UIKit import Vision +@objc(TiCoremlRealtimeRecognitionViewProxy) class TiCoremlRealtimeRecognitionViewProxy: TiViewProxy { private var currentSampleBuffer: CVImageBuffer? private var previewView: UIView? lazy private var request: VNCoreMLRequest = { - guard let model = try? MLModel(contentsOf: TiUtils.toURL(self.value(forKey: "model") as? String, proxy: self)) else { - fatalError("Error creating model") + guard let url = TiUtils.toURL(self.value(forKey: "model") as? String, proxy: self) else { + logErrorAndFail("Cannot load model from URL") + fatalError() + } + + if url.pathExtension == "modelc" { + logErrorAndFail("Please pass the .model file, not the .modelc") } - guard let visionModel = try? VNCoreMLModel(for: model) else { - fatalError("Error creating vision model") + guard let model = try? MLModel(contentsOf: MLModel.compileModel(at: url)) else { + logErrorAndFail("Error creating model") + fatalError() + } + var visionModel: VNCoreMLModel! + + do { + visionModel = try VNCoreMLModel(for: model) + } catch { + logErrorAndFail("Error creating vision model: \(error.localizedDescription)") + fatalError() } - + let _request = VNCoreMLRequest(model: visionModel) { request, error in - guard let observations = request.results else { + guard let observations = request.results as? [VNClassificationObservation] else { return } let result: [[String: Any]] = observations.map { [ - "identifier": $0.uuid, + "identifier": $0.identifier, + "uuid": $0.uuid.uuidString, "confidence": $0.confidence ] } @@ -46,20 +62,26 @@ class TiCoremlRealtimeRecognitionViewProxy: TiViewProxy { return _request; }() - lazy private var captureSession: TiCaptureSession = { - let session = TiCaptureSession(completionHandler: { imageBuffer in + private var _captureSession: TiCaptureSession! + + private func getCaptureSession() -> TiCaptureSession { + guard _captureSession == nil else { + return _captureSession + } + + _captureSession = TiCaptureSession(completionHandler: { imageBuffer in self.currentSampleBuffer = imageBuffer self.processRecognitionWithSampleBuffer() }) - self.view.layer.addSublayer(session.previewLayer) + self.view.layer.addSublayer(_captureSession.previewLayer) self.adjustFrame() - return session - }() + return _captureSession + } func adjustFrame() { - captureSession.previewLayer.frame = view.bounds; + getCaptureSession().previewLayer.frame = view.bounds; } private func processRecognitionWithSampleBuffer() { @@ -69,7 +91,7 @@ class TiCoremlRealtimeRecognitionViewProxy: TiViewProxy { do { try handler.perform([request]) } catch { - fatalError("Error processing buffer: \(error.localizedDescription)") + logErrorAndFail("Error processing buffer: \(error.localizedDescription)") } } } @@ -78,29 +100,31 @@ class TiCoremlRealtimeRecognitionViewProxy: TiViewProxy { extension TiCoremlRealtimeRecognitionViewProxy { - @objc func startRecognition(unused: Any?) { - if captureSession.captureSession.isRunning { - NSLog("[ERROR] Trying to start a capture session that is already running!") - return + @objc(startRecognition:) + func startRecognition(unused: Any?) { + if getCaptureSession().captureSession.isRunning { + return logErrorAndFail("Trying to start a capture session that is already running!") } - captureSession.start() + getCaptureSession().start() } - @objc func stopRecognition(unused: Any?) { - if !captureSession.captureSession.isRunning { - NSLog("[ERROR] Trying to stop a capture session that is not running!"); - return + @objc(stopRecognition:) + func stopRecognition(unused: Any?) { + if !getCaptureSession().captureSession.isRunning { + return logErrorAndFail("Trying to stop a capture session that is not running!"); } - captureSession.stop() + getCaptureSession().stop() } - @objc func isRecognizing(unused: Any?) -> Bool { - return captureSession.captureSession.isRunning + @objc(isRecognizing:) + func isRecognizing(unused: Any?) -> Bool { + return getCaptureSession().captureSession.isRunning } - @objc func takePicture(value: [Any]) { + @objc(takePicture:) + func takePicture(value: [Any]) { guard let sampleBuffer = currentSampleBuffer, let calback = value.first as? KrollCallback else { return diff --git a/README.md b/README.md index 8902c95..131d4a9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # iOS 11+ CoreML in Titanium -Use the native iOS 11+ "CoreML" framework in Axway Titanium. +Use the native iOS CoreML" framework in the Titanium SDK. ## Requirements -- [x] Titanium SDK 6.2.0 and later -- [x] iOS 11 and later -- [x] Compiled CoreML models (`xcrun coremlcompiler compile path/to/model.mlmodel /path/to/output`) +- [x] Titanium SDK 12.0.0 and later +- [x] Compiled CoreML model (compile with: `xcrun coremlcompiler compile path/to/model.mlmodel /path/to/output`) ## API's @@ -22,45 +21,19 @@ Use the native iOS 11+ "CoreML" framework in Axway Titanium. ### `isSupported()` (Boolean) ## Example -```js -var CoreML = require('ti.coreml'); - -var recognitionView = CoreML.createRealtimeRecognitionView({ - top: 40, - height: 300, - model: 'Inceptionv3.mlmodelc' -}); - -recognitionView.addEventListener('classification', function(e) { - Ti.API.info(e); -}); - -var win = Ti.UI.createWindow({ - backgroundColor: '#fff' -}); -win.add(recognitionView); +See example/app.js for details -var triggerButton = Ti.UI.createButton({ - bottom: 40, - title: 'Start Real-Time Recognition' -}); +## Compile Module -triggerButton.addEventListener('click', function() { - recognitionView.startRecognition(); -}); - -win.add(triggerButton); -win.open(); -``` - -## Build ```js -cd iphone -appc ti build -p ios --build-only +ti build -p ios --build-only ``` ## Legal -This module is Copyright (c) 2017-Present by Axway Appcelerator, Inc. All Rights Reserved. +Copyright (c) 2017-Present by Axway Appcelerator, Inc. +Copyright (c) 2022-Present by TiDev, Inc. + +All Rights Reserved. Usage of this module is subject to the Terms of Service agreement with Appcelerator, Inc. diff --git a/example/app.js b/example/app.js index e2746ea..2a2ee5a 100644 --- a/example/app.js +++ b/example/app.js @@ -1,37 +1,54 @@ -/** - * Ti.CoreML - * v1.0.0 Beta - - * @author Hans Knöchel - * @copyright Axway Appcelerator - * - */ - -var CoreML = require('ti.coreml'); - -var recognitionView = CoreML.createRealtimeRecognitionView({ - top: 40, - height: 300, - model: 'Inceptionv3.mlmodelc' -}); +import CoreML from 'ti.coreml'; -recognitionView.addEventListener('classification', function(e) { - Ti.API.info(e); -}); +let recognitionView, triggerButton; -var win = Ti.UI.createWindow({ +const win = Ti.UI.createWindow({ backgroundColor: '#fff' }); -win.add(recognitionView); - -var triggerButton = Ti.UI.createButton({ +win.addEventListener('close', () => { + if (recognitionView?.isRecognizing()) { + recognitionView.stopRecognition(); + } +}) + +const ButtonState = { + Start: 'Start Real-Time Recognition', + Stop: 'Stop Real-Time Recognition' +}; + +win.addEventListener('open', () => { + if (!CoreML.isSupported()) { + triggerButton.applyProperties({ title: '❌ Device not supported', enabled: false }); + return; + } + + recognitionView = CoreML.createRealtimeRecognitionView({ + top: 40, + height: 300, + model: 'Inceptionv3.mlmodel' + }); + + recognitionView.addEventListener('classification', ({ classifications }) => { + Ti.API.info(classifications); // Optionally sort by confidence and only log if >= threshold + }); +}) + +triggerButton = Ti.UI.createButton({ bottom: 40, - title: 'Start Real-Time Recognition' + title: ButtonState.Start }); -triggerButton.addEventListener('click', function() { - recognitionView.startRecognition(); +triggerButton.addEventListener('click', () => { + if (!recognitionView.isRecognizing()) { + recognitionView.startRecognition(); + triggerButton.title = ButtonState.Stop; + win.add(recognitionView); + } else { + recognitionView.stopRecognition(); + triggerButton.title = ButtonState.Start; + win.remove(recognitionView); + } }); win.add(triggerButton);