Allihoopa-macOS 1.2.1

Allihoopa-macOS 1.2.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2017年6月

Ali Baaba 维护。



  • mhallin

macOS 上的 Allihoopa SDK


Objective-C/Swift SDK,用于从 macOS 与 Allihoopa 交互。

如果您正在开发 iOS 应用,可以查看我们的 iOS SDK

安装

根据您的设置,安装 Allihoopa SDK 有多种方式。

如果您使用 CocoaPods,可以简单地将此 SDK 添加到您的 Podfile

target 'TargetName' do
  pod 'Allihoopa-macOS', '~> 1.2.1'
end

然后运行以下命令以下载依赖项

pod install

完成此操作后,您运行 carthage 以构建框架,然后将位于 Carthage/Build 文件夹中的 Allihoopa.framework 拖到您的项目中。

或者,您可以简单地从 Releases 标签 下载最新构建的框架。

手动构建

如果您愿意,可以将 Allihoopa-macOS 项目作为子项目包含到您的应用程序中,并将框架作为依赖项构建。在这种情况下,由于该项目与 iOS SDK 共享大量代码和功能,您还需要包含 AllihoopaCore-ObjC 作为依赖项。

如果您使用上述任何一种方法,此依赖项将自动为您管理。

配置

您需要将一个 URL 方案添加到应用程序的 Info.plist 中:ah-{APP_IDENTIFIER},例如,如果您的应用程序标识为 figure,则为 ah-figure。当您在 Allihoopa 中注册应用程序时,您将收到您的应用程序标识和 API 密钥。如果要开始加入,请发送电子邮件到 [email protected]

开发设置

请查看 SDKExample 文件夹以了解如何使用此 SDK。

API 文档

最新发布的 API 文档可在 http://cocoadocs.org/docsets/Allihoopa-macOS 上找到。

设置SDK

你需要一个类,例如你的应用代理,来实现AHAAllihoopaSDKDelegate以支持“打开”功能。下面是如何实现此功能的说明。

import Allihoopa

// In your UIApplicationDelegate implementation
func applicationDidFinishLaunching(_ aNotification: Notification) {
    AHAAllihoopaSDK.shared().setup([
        .applicationIdentifier: "your-application-identifier",
        .apiKey: "your-api-key",
        .delegate: self,
    ])
}
#import <Allihoopa/Allihoopa.h>

// In your UIApplicationDelegate implementation
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
    [[AHAAllihoopaSDK sharedInstance] setupWithConfiguration:@{
        AHAConfigKeyApplicationIdentifier: @"your-application-identifier",
        AHAConfigKeyAPIKey: @"your-api-key",
        AHAConfigKeySDKDelegate: self,
    }];
}

setupWithConfiguration:必须在调用任何其他API之前调用。如果SDK设置不正确,将抛出异常:如果缺少凭证或没有正确设置URL方案。有关更多信息,请参阅上面“设置SDK”部分。

配置字典支持以下键 - Objective-C与Swift中的名称

  • AHAConfigKeyApplicationIdentifier/.applicationIdentifier:必需的由Allihoopa提供的应用标识符的字符串。
  • AHAConfigKeyAPIKey/.apiKey:必需的包含应用程序API密钥的字符串。
  • AHAConfigKeySDKDelegate/.sdkDelegate:可选的实例,用于在用户尝试将物品导入应用时通知应用程序。如果提供,该实例必须符合AHAAllihoopaSDKDelegate协议。
  • AHAConfigKeyFacebookAppID/.facebookAppID:可选的包含应用程序的Facebook App ID的字符串。这将启用通过iOS内置的Accounts和Social框架进行二级社交分享。
  • AHAConfigKeyRegisterURLEventHandler/.registerURLEventHandler:可选的布尔值,指示SDK是否应注册自己的URL打开处理器。为方便起见,默认为true,因此如果你想要自己的URL事件处理器,**必须将其设置为false**。如果你将其设置为false,你必须在你的事件处理器中调用-handleOpenURL:(NSURL*)/handleOpen(url)

投放物品

let piece = try! AHADropPieceData(
    defaultTitle: "Default title", // The default title of the piece
    lengthMicroseconds: 40000000, // Length of the piece, in microseconds
    tempo: nil,
    loopMarkers: nil,
    timeSignature: nil,
    basedOn: [])

let vc = AHAAllihoopaSDK.shared().dropViewController(forPiece: piece, delegate: self)

self.presentViewControllerAsSheet(vc)
extension ViewController : AHADropDelegate {
    // The drop view controller will ask your application for audio data.
    // You should perform work in the background and call the completion
    // handler on the main queue. If you already have the data available,
    // you can just call the completion handler directly.
    //
    // This method *must* call completion with a data bundle for the drop to
    // succeed. If it doesn't, an error screen will be shown.
    func renderMixStem(forPiece piece: AHADropPieceData, completion: @escaping (AHAAudioDataBundle?, Error?) -> Void) {
        DispatchQueue.global().async {
            // Render Wave data into an NSData object
            let bundle = AHAAudioDataBundle(format: .wave, data: data)
            DispatchQueue.main.async {
                completion(bundle, nil)
            }
        }
    }

    // You are responsible for dismissing the drop view controller in a
    // suitable way, matching how you presented it.
    func dropViewController(_ sender: NSViewController, willClose piece: AHADropPieceData, successfulDrop: Bool) {
        self.dismissViewController(sender)
    }
}

NSError* error;
AHADropPieceData* piece = [[AHADropPieceData alloc] initWithDefaultTitle:@"Default title"
                                                      lengthMicroseconds:40000000
                                                                   tempo:nil
                                                             loopMarkers:nil
                                                           timeSignature:nil
                                                         basedOnPieceIDs:@[]
                                                                   error:&error];
if (piece) {
    UIViewController* vc = [[AHAAllihoopaSDK sharedInstance] dropViewControllerForPiece:piece delegate:self];
    [self presentViewControllerAsSheet:vc];
}
@implementation ViewController

- (void)renderMixStemForPiece:(AHADropPieceData *)piece
                   completion:(void (^)(AHAAudioDataBundle * _Nullable, NSError * _Nullable))completion {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Render wave data into an NSData object
        AHAAudioDataBundle* bundle = [[AHAAudioDataBundle alloc] initWithFormat:AHAAudioFormatWave data:data];

        dispatch_async(dispatch_get_main_queue(), ^{
            completion(bundle, nil);
        });
    });
}

- (void)dropViewController:(NSViewController*)sender
         forPieceWillClose:(AHADropPieceData*)piece
       afterSuccessfulDrop:(BOOL)successfulDrop {
    [self dismissViewController:sender];
}

@end

dropViewController创建一个视图控制器,它将使用委托对象帮助投放你提供的物品。如果用户未登录,SDK将在用户的默认浏览器中打开登录对话框,并在用户登录后继续。当用户想关闭投放视图时,委托将被通知,并且必须解散视图控制器。

一个物品可以包含不同类型的元数据。上面的示例显示了我们所需要的最小数据量:默认标题、物品音频数据的长度以及将音频渲染成已知格式的委托方法。

AHADropPieceData会对输入执行基本验证:它将返回包含错误信息的NSError。错误可能包括标记倒置或长度超出合理范围等问题。这些基本上是程序员错误 - 而不是可以以有意义方式处理的运行时错误。

如果你的应用程序了解这一点,它可以向AHADropPieceData提供更多信息,以及在AHADropDelegate上实现比上面显示更多的方法。以下是一个完整示例,显示了你可以设置的所有数据。

let piece = try! AHADropPieceData(
    defaultTitle: "Default title",
    lengthMicroseconds: 100000000,
    // The fixed tempo in BPM. Allowed range: 1 - 999.999 BPM
    tempo: AHAFixedTempo(fixedTempo: 128), 

    // If the piece is a loop, you can provide the loop markers.
    loopMarkers: AHALoopMarkers(startMicroseconds: 0, endMicroseconds: 500000),

    // If the time signature is available and fixed, you can provide a time
    // signature object.
    //
    // The upper numeral can range from 1 to 16, incnlusive. The lower numeral
    // must be one of 2, 4, 8, and 16.
    timeSignature: AHATimeSignature(upper: 8, lower: 4),

    // If the piece is based on other pieces, provide a list of the IDs of those
    // pieces here.
    basedOn: [],

    // If the piece has a known tonality, provide the scale and root here.
    // Other values are AHATonality.unknown() (default if omitted), and
    // AHATonality.atonal() for pieces that contain audio that doesn't have a
    // tonality, e.g. drum loops.
    tonality: AHATonality(tonalScale: AHAGetMajorScale(4), root: 4)
)
extension ViewController : AHADropDelegate {
    // The "mix stem" is the audio data that should be used to place the piece
    // on a timeline. Call the completion handler with a data bundle instance
    // on the main queue when data is available.
    //
    // The mix stem is mandatory.
    func renderMixStem(forPiece piece: AHADropPieceData, completion: @escaping (AHAAudioDataBundle?, Error?) -> Void) {
    }

    // You can supply a default cover image that the user can upload or change.
    // Call the completion handler with an image of size 640x640 px, or nil.
    func renderCoverImage(forPiece piece: AHADropPieceData, completion: @escaping (UIImage?) -> Void) {
        completion(nil)
    }

    // If the audio to be placed on the timeline is different from what users
    // should listen to, use this delegate method to provide a "preview"
    // audio bundle.
    //
    // For example, if you're providing a short loop you can supply only the
    // loop data in a lossless format as the mix stem, and then a longer track
    // containing a few loops with fade in/out in a lossy format in the
    // preview audio.
    //
    // The preview audio is what's going to be played on the website.
    //
    // If no preview audio is provided, the mix stem will be used instead. This
    // replacement is done server-side, the mix stem data will only be uploaded
    // once from the client.
    func renderPreviewAudio(forPiece piece: AHADropPieceData, completion: @escaping (AHAAudioDataBundle?, Error?) -> Void) {
    }
    
    // You can include an application specific attachment, which can be of 
    // arbitrary file type referred by a registered MIME type
    func renderAttachment(forPiece piece: AHADropPieceData, completion: @escaping (AHAAttachmentBundle?, Error?) -> Void) {
    }
}

有关音调和其他字段的更多信息,请参阅iOS SDK文档

导入物品

当用户在网站中选择“在[你的应用]中打开”时,SDK将获取请求,获取物品元数据,并调用openPieceFromAllihoopa:error:,其中包括用户想要打开的物品。AHAPiece实例有用于下载指定格式的音频数据的方法,你可以使用这些方法将音频导入当前文档或保存以供以后使用。AHAPiece还包含与AHADropPiece类似的元数据。

func openPiece(fromAllihoopa piece: AHAPiece?, error: Error?) {
    if let piece = piece {
        // The user wanted to open a piece

        // Download the mix stem audio in Ogg format. You can also use .wave
        piece.downloadMixStem(format: .oggVorbis, completion: { (data, error) in
            if let data = data {
                // Data downloaded successfully
            }
        })
    }
    else {
        // Handle the error
        //
        // This should not *usually* happen, but if the piece was removed after
        // opening, or if there were some connection issues we can end up here
    }
}
- (void)openPieceFromAllihoopa:(AHAPiece*)piece error:(NSError*)error {
    if (piece != nil) {
        // The user wanted to open a piece
        [piece downloadMixStemWithFormat:AHAAudioFormatOggVorbis completion:^(NSData* data, NSError* error) {
            if (data != nil) {
                // Data downloaded successfully
            }
        }];
    }
    else {
        // Handle the error
    }
}

附件

您还可以在降落碎片时包含特定应用的附件,并在导入碎片时类似地下载该附件。附件可以是任意文件类型,并通过MIME类型字符串引用。必须在Allihoopa服务中预先注册MIME类型,即如果您应用程序需要使用附件,请通过发送电子邮件至[email protected]进行注册。

特定应用附件可以包含在降落代理对象中。

extension ViewController : AHADropDelegate {
    // ...
    
    // You can include an application specific attachment along other asset files
    func renderAttachment(forPiece piece: AHADropPieceData, completion: @escaping (AHAAttachmentBundle?, Error?) -> Void) {
        DispatchQueue.global().async {
            do {
                let data = try Data(contentsOf: Bundle.main.url(forResource: "figure_song", withExtension: "xml")!)
                let bundle = AHAAttachmentBundle(mimeType: "application/figure", data: data)
                
                DispatchQueue.main.async {
                    completion(bundle, nil)
                }
            }
            catch let error {
                DispatchQueue.main.async {
                    completion(nil, error)
                }
            }
        }
    }
}

导入碎片时,可以使用相同的MIME类型下载附件。

func openPiece(fromAllihoopa piece: AHAPiece?, error: Error?) {
    if let piece = piece {
        // ...
    
        // Download an attachment based on specific MIME type
        piece.downloadAttachment(mimeType: "application/figure", completion: { (data, error) in
            if let data = data {
                // Data downloaded successfully
            }
        })
    }
}