26 changed files with 2375 additions and 52 deletions
@ -0,0 +1,379 @@ |
|||||
|
Flutter crash report. |
||||
|
Please report a bug at https://github.com/flutter/flutter/issues. |
||||
|
|
||||
|
## command |
||||
|
|
||||
|
flutter build ios |
||||
|
|
||||
|
## exception |
||||
|
|
||||
|
ProcessException: ProcessException: Process exited abnormally with exit code -6: |
||||
|
Command line invocation: |
||||
|
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -list |
||||
|
|
||||
|
User defaults from command line: |
||||
|
IDEPackageSupportUseBuiltinSCM = YES |
||||
|
|
||||
|
Resolve Package Graph |
||||
|
|
||||
|
Fetching from https://github.com/apple/swift-log.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/apple/swift-protobuf.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/firebase/leveldb.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/abseil-cpp-binary.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/apple/swift-http-types (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/app-check.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/interop-ios-for-google-sdks.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/SDWebImage/SDWebImage (cached) |
||||
|
|
||||
|
Fetching from https://github.com/ybrid/opus-swift.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/GTMAppAuth.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/GoogleSignIn-iOS.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/TimOliver/TOCropViewController (cached) |
||||
|
|
||||
|
Fetching from https://github.com/zhangao0086/DKImagePickerController (cached) |
||||
|
|
||||
|
Fetching from https://github.com/zhangao0086/DKCamera (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/gtm-session-fetcher.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/GoogleDataTransport.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/firebase/flutterfire (cached) |
||||
|
|
||||
|
Fetching from https://github.com/SnapKit/SnapKit.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/apple/swift-openapi-runtime (cached) |
||||
|
|
||||
|
Fetching from https://github.com/Alamofire/Alamofire.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/apple/swift-system.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/firebase/nanopb.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/promises.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/GoogleAppMeasurement.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/kirualex/SwiftyGif.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/grpc-binary.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/google/GoogleUtilities.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/MacPaw/OpenAI.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/zhangao0086/DKPhotoGallery (cached) |
||||
|
|
||||
|
Fetching from https://github.com/loopwork-ai/eventsource.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/openid/AppAuth-iOS.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/modelcontextprotocol/swift-sdk.git (cached) |
||||
|
|
||||
|
Fetching from https://github.com/firebase/firebase-ios-sdk (cached) |
||||
|
|
||||
|
Creating working copy of package ‘abseil-cpp-binary’ |
||||
|
|
||||
|
Checking out 1.2024072200.0 of package ‘abseil-cpp-binary’ |
||||
|
|
||||
|
Creating working copy of package ‘app-check’ |
||||
|
|
||||
|
Checking out 11.2.0 of package ‘app-check’ |
||||
|
|
||||
|
Creating working copy of package ‘opus-swift’ |
||||
|
|
||||
|
Checking out 0.8.0 of package ‘opus-swift’ |
||||
|
|
||||
|
Creating working copy of package ‘SDWebImage’ |
||||
|
|
||||
|
Checking out 5.21.0 of package ‘SDWebImage’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-http-types’ |
||||
|
|
||||
|
Checking out 1.4.0 of package ‘swift-http-types’ |
||||
|
|
||||
|
Creating working copy of package ‘interop-ios-for-google-sdks’ |
||||
|
|
||||
|
Checking out 101.0.0 of package ‘interop-ios-for-google-sdks’ |
||||
|
|
||||
|
Creating working copy of package ‘leveldb’ |
||||
|
|
||||
|
Checking out 1.22.5 of package ‘leveldb’ |
||||
|
|
||||
|
Creating working copy of package ‘GTMAppAuth’ |
||||
|
|
||||
|
Checking out 4.1.1 of package ‘GTMAppAuth’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-log’ |
||||
|
|
||||
|
Checking out 1.6.3 of package ‘swift-log’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-protobuf’ |
||||
|
|
||||
|
Checking out 1.29.0 of package ‘swift-protobuf’ |
||||
|
|
||||
|
Creating working copy of package ‘GoogleSignIn-iOS’ |
||||
|
|
||||
|
Checking out 8.0.0 of package ‘GoogleSignIn-iOS’ |
||||
|
|
||||
|
Creating working copy of package ‘DKCamera’ |
||||
|
|
||||
|
Checking out master (5c691d1) of package ‘DKCamera’ |
||||
|
|
||||
|
Creating working copy of package ‘gtm-session-fetcher’ |
||||
|
|
||||
|
Checking out 3.5.0 of package ‘gtm-session-fetcher’ |
||||
|
|
||||
|
Creating working copy of package ‘TOCropViewController’ |
||||
|
|
||||
|
Checking out 2.7.4 of package ‘TOCropViewController’ |
||||
|
|
||||
|
Creating working copy of package ‘DKImagePickerController’ |
||||
|
|
||||
|
Checking out 4.3.9 (0bdfeac) of package ‘DKImagePickerController’ |
||||
|
|
||||
|
Creating working copy of package ‘GoogleDataTransport’ |
||||
|
|
||||
|
Checking out 10.1.0 of package ‘GoogleDataTransport’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-openapi-runtime’ |
||||
|
|
||||
|
Checking out 1.8.2 of package ‘swift-openapi-runtime’ |
||||
|
|
||||
|
Creating working copy of package ‘flutterfire’ |
||||
|
|
||||
|
Checking out main (f852df8) of package ‘flutterfire’ |
||||
|
|
||||
|
Creating working copy of package ‘SnapKit’ |
||||
|
|
||||
|
Checking out 5.7.1 of package ‘SnapKit’ |
||||
|
|
||||
|
Creating working copy of package ‘Alamofire’ |
||||
|
|
||||
|
Checking out 5.10.2 of package ‘Alamofire’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-system’ |
||||
|
|
||||
|
Checking out 1.5.0 of package ‘swift-system’ |
||||
|
|
||||
|
Creating working copy of package ‘nanopb’ |
||||
|
|
||||
|
Checking out 2.30910.0 of package ‘nanopb’ |
||||
|
|
||||
|
Creating working copy of package ‘GoogleAppMeasurement’ |
||||
|
|
||||
|
Checking out 11.13.0 of package ‘GoogleAppMeasurement’ |
||||
|
|
||||
|
Creating working copy of package ‘promises’ |
||||
|
|
||||
|
Checking out 2.4.0 of package ‘promises’ |
||||
|
|
||||
|
Creating working copy of package ‘SwiftyGif’ |
||||
|
|
||||
|
Checking out 5.4.5 of package ‘SwiftyGif’ |
||||
|
|
||||
|
Creating working copy of package ‘grpc-binary’ |
||||
|
|
||||
|
Checking out 1.69.0 of package ‘grpc-binary’ |
||||
|
|
||||
|
Creating working copy of package ‘GoogleUtilities’ |
||||
|
|
||||
|
Checking out 8.1.0 of package ‘GoogleUtilities’ |
||||
|
|
||||
|
Creating working copy of package ‘OpenAI’ |
||||
|
|
||||
|
Checking out 0.4.3 of package ‘OpenAI’ |
||||
|
|
||||
|
Creating working copy of package ‘DKPhotoGallery’ |
||||
|
|
||||
|
Checking out master (311c1bc) of package ‘DKPhotoGallery’ |
||||
|
|
||||
|
Creating working copy of package ‘eventsource’ |
||||
|
|
||||
|
Checking out 1.1.1 of package ‘eventsource’ |
||||
|
|
||||
|
Creating working copy of package ‘AppAuth-iOS’ |
||||
|
|
||||
|
Checking out 1.7.6 of package ‘AppAuth-iOS’ |
||||
|
|
||||
|
Creating working copy of package ‘swift-sdk’ |
||||
|
|
||||
|
Checking out 0.9.0 of package ‘swift-sdk’ |
||||
|
|
||||
|
Creating working copy of package ‘firebase-ios-sdk’ |
||||
|
|
||||
|
Checking out 11.13.0 of package ‘firebase-ios-sdk’ |
||||
|
|
||||
|
'agent_service' dependency on '/Users/liwei/work/flutter/deepvoice_client/local_plugins/music_service/ios/user_portrait' conflicts with dependency on '/Users/liwei/work/flutter/deepvoice_client/local_plugins/user_portrait/ios/user_portrait' which has the same identity 'user_portrait'. this will be escalated to an error in future versions of SwiftPM. |
||||
|
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSMutableArray insertObjects:atIndexes:]: count of array (62) differs from count of index set (61)' |
||||
|
*** First throw call stack: |
||||
|
( |
||||
|
0 CoreFoundation 0x0000000188e62ca0 __exceptionPreprocess + 176 |
||||
|
1 libobjc.A.dylib 0x0000000188926b90 objc_exception_throw + 88 |
||||
|
2 CoreFoundation 0x0000000188f5d1dc -[__NSCFString characterAtIndex:].cold.1 + 0 |
||||
|
3 CoreFoundation 0x0000000188e490b8 -[NSMutableArray insertObjects:atIndexes:] + 1444 |
||||
|
4 IDEFoundation 0x000000010ce72874 __50-[IDEGroup insertGroupSubitems:atIndexes:context:]_block_invoke + 1084 |
||||
|
5 DVTFoundation 0x000000010b67b16c -[DVTModelObjectGraph performBlockCoalescingModelChanges:] + 60 |
||||
|
6 IDEFoundation 0x000000010ce72398 -[IDEGroup insertGroupSubitems:atIndexes:context:] + 248 |
||||
|
7 DVTFoundation 0x000000010b639c30 -[NSMutableArray(DVTFoundationClassAdditions) dvt_sortedInsertOfObjects:withComparator:] + 184 |
||||
|
8 IDESwiftPackageCore 0x000000011a08c15c $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC32registerDependencyFileReferences33_033DB97E8C2A552F3158921835EE9F98LL_27modelGraphSynchronizerTokenySayAA0abgH9ReferenceO010dependencyU0_AC16Reg 9 IDESwiftPackageCore 0x000000011a08f264 $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC27dependencyPackagesDidUpdate33_033DB97E8C2A552F3158921835EE9F98LL8packages14graphHasErrors25revalidatedFilePathCaches27modelGraphSynchronizerToke 10 IDESwiftPackageCore 0x000000011a08717c $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC27packageGraphDidFinishAction_8duration6resulty7SwiftPM12SPMWorkspaceC0bgJ0O_SdAG0oebgJ16ResolutionResultOtYaFyAC05ModelG17SynchronizerToken33_033 11 IDESwiftPackageCore 0x000000011a08ac18 $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC38disableWorkspaceContentSynchronization33_033DB97E8C2A552F3158921835EE9F98LL6duringyyAC27ModelGraphSynchronizerTokenAELLVXE_tFyyXEfU_TA + 20 |
||||
|
12 DVTFoundation 0x000000010b84fd68 $sSo19DVTModelObjectGraphC13DVTFoundationE34performBlockCoalescingModelChangesyxxyXElFyyXEfU_ + 104 |
||||
|
13 DVTFoundation 0x000000010b8134bc $sSDySSSo8NSObjectCGIgo_ACIego_TR + 20 |
||||
|
14 DVTFoundation 0x000000010b84fa80 $sIeg_IyB_TR + 20 |
||||
|
15 DVTFoundation 0x000000010b67b24c __58-[DVTModelObjectGraph performBlockCoalescingModelChanges:]_block_invoke + 104 |
||||
|
16 DVTFoundation 0x000000010b674cf8 -[DVTModelGraphTransactionScope performTransaction:] + 60 |
||||
|
17 DVTFoundation 0x000000010b67b1c4 -[DVTModelObjectGraph performBlockCoalescingModelChanges:] + 148 |
||||
|
18 DVTFoundation 0x000000010b850520 $sSo19DVTModelObjectGraphC13DVTFoundationE34performBlockCoalescingModelChangesyxxyXElF + 344 |
||||
|
19 IDESwiftPackageCore 0x000000011a07d32c $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC38disableWorkspaceContentSynchronization33_033DB97E8C2A552F3158921835EE9F98LL6duringyyAC27ModelGraphSynchronizerTokenAELLVXE_tF + 444 |
||||
|
20 IDESwiftPackageCore 0x000000011a086198 $s19IDESwiftPackageCore23IDESPMWorkspaceDelegateC27packageGraphDidFinishAction_8duration6resulty7SwiftPM12SPMWorkspaceC0bgJ0O_SdAG0oebgJ16ResolutionResultOtYaFTY4_ + 164 |
||||
|
21 IDESwiftPackageCore 0x000000011a05ba31 $sIeAgH_ytIeAgHr_TRTATQ0_ + 1 |
||||
|
22 SwiftPM 0x000000014800cda5 $s7SwiftPM12SPMWorkspaceC26packageGraphActionFinished33_918CA8CFEB8D3E06D2EEA2771EA5EA00LLyyAC07PackageE16ResolutionResultAELLVYaFTQ1_ + 1 |
||||
|
23 SwiftPM 0x000000014800c6c1 $s7SwiftPM12SPMWorkspaceC46processPackageGraphActionsInBackgroundIfNeeded33_918CA8CFEB8D3E06D2EEA2771EA5EA00LL010canProcessefG0yAC11AffirmativeO_tFyyYaYbcfU1_yyYacfU0_TQ1_ + 1 |
||||
|
24 SwiftPM 0x000000014805b871 $s7SwiftPM33SPMWorkspaceOrchestrationDelegateP27packageGraphDidFinishAction_8duration6resultyAA0C0C07PackagegJ0O_SdAA0cemgJ16ResolutionResultOtYaFTjTQ0_ + 1 |
||||
|
25 SwiftPM 0x00000001480d07f1 $sxIeAgHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRyt_Tg5TQ0_ + 1 |
||||
|
26 SwiftPM 0x0000000148057ff9 $sxIeAgHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRyt_Tg5TATQ0_ + 1 |
||||
|
27 libswift_Concurrency.dylib 0x0000000271af883d _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1 |
||||
|
) |
||||
|
** INTERNAL ERROR: Uncaught exception ** |
||||
|
Uncaught Exception: *** -[NSMutableArray insertObjects:atIndexes:]: count of array (62) differs from count of index set (61) |
||||
|
Stack: |
||||
|
0 __exceptionPreprocess (in CoreFoundation) |
||||
|
1 objc_exception_throw (in libobjc.A.dylib) |
||||
|
2 -[__NSCFString characterAtIndex:].cold.1 (in CoreFoundation) |
||||
|
3 -[NSMutableArray insertObjects:atIndexes:] (in CoreFoundation) |
||||
|
4 __50-[IDEGroup insertGroupSubitems:atIndexes:context:]_block_invoke (in IDEFoundation) |
||||
|
5 -[DVTModelObjectGraph performBlockCoalescingModelChanges:] (in DVTFoundation) |
||||
|
6 -[IDEGroup insertGroupSubitems:atIndexes:context:] (in IDEFoundation) |
||||
|
7 -[NSMutableArray(DVTFoundationClassAdditions) dvt_sortedInsertOfObjects:withComparator:] (in DVTFoundation) |
||||
|
8 specialized IDESPMWorkspaceDelegate.registerDependencyFileReferences(_:modelGraphSynchronizerToken:) (in IDESwiftPackageCore) |
||||
|
9 specialized IDESPMWorkspaceDelegate.dependencyPackagesDidUpdate(packages:graphHasErrors:revalidatedFilePathCaches:modelGraphSynchronizerToken:) (in IDESwiftPackageCore) |
||||
|
10 closure #1 in IDESPMWorkspaceDelegate.packageGraphDidFinishAction(_:duration:result:) (in IDESwiftPackageCore) |
||||
|
11 partial apply for closure #1 in IDESPMWorkspaceDelegate.disableWorkspaceContentSynchronization(during:) (in IDESwiftPackageCore) |
||||
|
12 <deduplicated_symbol> (in DVTFoundation) |
||||
|
13 <deduplicated_symbol> (in DVTFoundation) |
||||
|
14 thunk for @escaping @callee_guaranteed () -> () (in DVTFoundation) |
||||
|
15 __58-[DVTModelObjectGraph performBlockCoalescingModelChanges:]_block_invoke (in DVTFoundation) |
||||
|
16 -[DVTModelGraphTransactionScope performTransaction:] (in DVTFoundation) |
||||
|
17 -[DVTModelObjectGraph performBlockCoalescingModelChanges:] (in DVTFoundation) |
||||
|
18 DVTModelObjectGraph.performBlockCoalescingModelChanges<A>(_:) (in DVTFoundation) |
||||
|
19 IDESPMWorkspaceDelegate.disableWorkspaceContentSynchronization(during:) (in IDESwiftPackageCore) |
||||
|
20 IDESPMWorkspaceDelegate.packageGraphDidFinishAction(_:duration:result:) (in IDESwiftPackageCore) |
||||
|
21 <deduplicated_symbol> (in IDESwiftPackageCore) |
||||
|
22 SPMWorkspace.packageGraphActionFinished(_:) (in SwiftPM) |
||||
|
23 closure #2 in closure #3 in SPMWorkspace.processPackageGraphActionsInBackgroundIfNeeded(canProcessPackageGraphActions:) (in SwiftPM) |
||||
|
24 <deduplicated_symbol> (in SwiftPM) |
||||
|
25 specialized thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) (in SwiftPM) |
||||
|
26 <deduplicated_symbol> (in SwiftPM) |
||||
|
27 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) (in libswift_Concurrency.dylib) |
||||
|
Command: /usr/bin/arch -arm64e xcrun xcodebuild -list |
||||
|
|
||||
|
``` |
||||
|
#0 RunResult.throwException (package:flutter_tools/src/base/process.dart:118:5) |
||||
|
#1 _DefaultProcessUtils.run (package:flutter_tools/src/base/process.dart:344:19) |
||||
|
<asynchronous suspension> |
||||
|
#2 XcodeProjectInterpreter.getInfo (package:flutter_tools/src/ios/xcodeproj.dart:334:30) |
||||
|
<asynchronous suspension> |
||||
|
#3 XcodeBasedProject.projectInfo (package:flutter_tools/src/xcode_project.dart:197:29) |
||||
|
<asynchronous suspension> |
||||
|
#4 XcodeBasedProject.buildSettingsForBuildInfo (package:flutter_tools/src/xcode_project.dart:217:36) |
||||
|
<asynchronous suspension> |
||||
|
#5 IosProject._parseProductName (package:flutter_tools/src/xcode_project.dart:647:55) |
||||
|
<asynchronous suspension> |
||||
|
#6 IosProject.productName (package:flutter_tools/src/xcode_project.dart:635:29) |
||||
|
<asynchronous suspension> |
||||
|
#7 BuildableIOSApp.fromProject (package:flutter_tools/src/ios/application_package.dart:117:33) |
||||
|
<asynchronous suspension> |
||||
|
#8 FlutterApplicationPackageFactory.getPackageForPlatform (package:flutter_tools/src/flutter_application_package.dart:80:15) |
||||
|
<asynchronous suspension> |
||||
|
#9 _BuildIOSSubCommand.buildableIOSApp.<anonymous closure> (package:flutter_tools/src/commands/build_ios.dart:707:9) |
||||
|
<asynchronous suspension> |
||||
|
#10 _BuildIOSSubCommand.runCommand (package:flutter_tools/src/commands/build_ios.dart:748:33) |
||||
|
<asynchronous suspension> |
||||
|
#11 FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1563:27) |
||||
|
<asynchronous suspension> |
||||
|
#12 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:154:19) |
||||
|
<asynchronous suspension> |
||||
|
#13 CommandRunner.runCommand (package:args/command_runner.dart:212:13) |
||||
|
<asynchronous suspension> |
||||
|
#14 FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:494:9) |
||||
|
<asynchronous suspension> |
||||
|
#15 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:154:19) |
||||
|
<asynchronous suspension> |
||||
|
#16 FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:431:5) |
||||
|
<asynchronous suspension> |
||||
|
#17 run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:98:11) |
||||
|
<asynchronous suspension> |
||||
|
#18 AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:154:19) |
||||
|
<asynchronous suspension> |
||||
|
#19 main (package:flutter_tools/executable.dart:102:3) |
||||
|
<asynchronous suspension> |
||||
|
``` |
||||
|
|
||||
|
## flutter doctor |
||||
|
|
||||
|
``` |
||||
|
[32m[✓][39m Flutter (Channel stable, 3.32.3, on macOS 15.5 24F74 darwin-arm64, locale zh-Hans-CN) [429ms] |
||||
|
[32m•[39m Flutter version 3.32.3 on channel stable at /Users/liwei/flutter |
||||
|
[32m•[39m Upstream repository https://github.com/flutter/flutter.git |
||||
|
[32m•[39m Framework revision 5c1433509f (9 weeks ago), 2025-06-11 13:12:24 -0700 |
||||
|
[32m•[39m Engine revision 31c4875c7a |
||||
|
[32m•[39m Dart version 3.8.1 |
||||
|
[32m•[39m DevTools version 2.45.1 |
||||
|
|
||||
|
[33m[!][39m Android toolchain - develop for Android devices (Android SDK version 36.0.0) [2.8s] |
||||
|
[32m•[39m Android SDK at /Users/liwei/Library/Android/sdk |
||||
|
[32m•[39m Platform android-36, build-tools 36.0.0 |
||||
|
[32m•[39m Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java |
||||
|
This is the JDK bundled with the latest Android Studio installation on this machine. |
||||
|
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`. |
||||
|
[32m•[39m Java version OpenJDK Runtime Environment (build 21.0.4+-12422083-b607.1) |
||||
|
[33m![39m Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses |
||||
|
|
||||
|
[32m[✓][39m Xcode - develop for iOS and macOS (Xcode 16.2) [1,682ms] |
||||
|
[32m•[39m Xcode at /Applications/Xcode.app/Contents/Developer |
||||
|
[32m•[39m Build 16C5032a |
||||
|
[32m•[39m CocoaPods version 1.16.2 |
||||
|
|
||||
|
[32m[✓][39m Chrome - develop for the web [6ms] |
||||
|
[32m•[39m Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome |
||||
|
|
||||
|
[32m[✓][39m Android Studio (version 2024.2) [5ms] |
||||
|
[32m•[39m Android Studio at /Applications/Android Studio.app/Contents |
||||
|
[32m•[39m Flutter plugin can be installed from: |
||||
|
🔨 https://plugins.jetbrains.com/plugin/9212-flutter |
||||
|
[32m•[39m Dart plugin can be installed from: |
||||
|
🔨 https://plugins.jetbrains.com/plugin/6351-dart |
||||
|
[32m•[39m Java version OpenJDK Runtime Environment (build 21.0.4+-12422083-b607.1) |
||||
|
|
||||
|
[32m[✓][39m VS Code (version 1.103.0) [4ms] |
||||
|
[32m•[39m VS Code at /Applications/Visual Studio Code.app/Contents |
||||
|
[32m•[39m Flutter extension version 3.116.0 |
||||
|
|
||||
|
[32m[✓][39m Connected device (5 available) [9.4s] |
||||
|
[32m•[39m RMX3310 (mobile) • a709b98b • android-arm64 • Android 14 (API 34) |
||||
|
[32m•[39m Voitrans的iPhoneXr (wireless) (mobile) • 00008020-000175D23C03002E • ios • iOS 18.6 22G86 |
||||
|
[32m•[39m iPhone XR (wireless) (mobile) • 00008020-000140140260802E • ios • iOS 18.5 22F76 |
||||
|
[32m•[39m macOS (desktop) • macos • darwin-arm64 • macOS 15.5 24F74 darwin-arm64 |
||||
|
[32m•[39m Chrome (web) • chrome • web-javascript • Google Chrome 139.0.7258.67 |
||||
|
[33m![39m Error: Browsing on the local area network for 李伟的iPad. Ensure the device is unlocked and attached with a cable or |
||||
|
associated with the same local area network as this Mac. |
||||
|
The device must be opted into Developer Mode to connect wirelessly. (code -27) |
||||
|
[33m![39m Error: Browsing on the local area network for liwei. Ensure the device is unlocked and attached with a cable or |
||||
|
associated with the same local area network as this Mac. |
||||
|
The device must be opted into Developer Mode to connect wirelessly. (code -27) |
||||
|
|
||||
|
[32m[✓][39m Network resources [5.1s] |
||||
|
[32m•[39m All expected network resources are available. |
||||
|
|
||||
|
[33m![39m Doctor found issues in 1 category. |
||||
|
``` |
||||
@ -0,0 +1,47 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
|
<plist version="1.0"> |
||||
|
<dict> |
||||
|
<key>AvailableLibraries</key> |
||||
|
<array> |
||||
|
<dict> |
||||
|
<key>BinaryPath</key> |
||||
|
<string>libQPlayAutoSDK-x86_64.a</string> |
||||
|
<key>HeadersPath</key> |
||||
|
<string>Headers</string> |
||||
|
<key>LibraryIdentifier</key> |
||||
|
<string>ios-x86_64-simulator</string> |
||||
|
<key>LibraryPath</key> |
||||
|
<string>libQPlayAutoSDK-x86_64.a</string> |
||||
|
<key>SupportedArchitectures</key> |
||||
|
<array> |
||||
|
<string>x86_64</string> |
||||
|
</array> |
||||
|
<key>SupportedPlatform</key> |
||||
|
<string>ios</string> |
||||
|
<key>SupportedPlatformVariant</key> |
||||
|
<string>simulator</string> |
||||
|
</dict> |
||||
|
<dict> |
||||
|
<key>BinaryPath</key> |
||||
|
<string>libQPlayAutoSDK-arm64.a</string> |
||||
|
<key>HeadersPath</key> |
||||
|
<string>Headers</string> |
||||
|
<key>LibraryIdentifier</key> |
||||
|
<string>ios-arm64</string> |
||||
|
<key>LibraryPath</key> |
||||
|
<string>libQPlayAutoSDK-arm64.a</string> |
||||
|
<key>SupportedArchitectures</key> |
||||
|
<array> |
||||
|
<string>arm64</string> |
||||
|
</array> |
||||
|
<key>SupportedPlatform</key> |
||||
|
<string>ios</string> |
||||
|
</dict> |
||||
|
</array> |
||||
|
<key>CFBundlePackageType</key> |
||||
|
<string>XFWK</string> |
||||
|
<key>XCFrameworkFormatVersion</key> |
||||
|
<string>1.0</string> |
||||
|
</dict> |
||||
|
</plist> |
||||
@ -0,0 +1,7 @@ |
|||||
|
//
|
||||
|
// QPlayAutoSDK.h
|
||||
|
// QPlayAutoSDK Umbrella Header
|
||||
|
//
|
||||
|
|
||||
|
#import "include/QPlayAutoSDK.h" |
||||
|
#import "include/QPlayAutoDefine.h" |
||||
@ -0,0 +1,5 @@ |
|||||
|
framework module QPlayAutoSDK { |
||||
|
umbrella header "QPlayAutoSDK.h" |
||||
|
export * |
||||
|
module * { export * } |
||||
|
} |
||||
Binary file not shown.
@ -0,0 +1,7 @@ |
|||||
|
//
|
||||
|
// QPlayAutoSDK.h
|
||||
|
// QPlayAutoSDK Umbrella Header
|
||||
|
//
|
||||
|
|
||||
|
#import "include/QPlayAutoSDK.h" |
||||
|
#import "include/QPlayAutoDefine.h" |
||||
@ -0,0 +1,238 @@ |
|||||
|
//
|
||||
|
// QPlayAutoDefine.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/17.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef QPlayAutoDefine_h |
||||
|
#define QPlayAutoDefine_h |
||||
|
|
||||
|
extern NSString *const kQPlayAutoItemRootID; |
||||
|
extern NSString *const kQPlayAutoArgument_Count; |
||||
|
extern NSString *const kQPlayAutoArgument_PageIndex; |
||||
|
extern NSString *const kQPlayAutoArgument_ParentID; |
||||
|
extern NSString *const kQPlayAutoArgument_Lists; |
||||
|
extern NSString *const kQPlayAutoArgument_PlayMode; |
||||
|
extern NSString *const kQPlayAutoArgument_IsFav; |
||||
|
extern NSString *const kQPlayAutoArgument_Position; |
||||
|
extern NSString *const kQPlayAutoArgument_Song; |
||||
|
extern NSString *const kQPlayAutoArgument_SongID; |
||||
|
extern NSString *const kQPlayAutoArgument_State; |
||||
|
extern NSString *const kQPlayAutoArgument_Error; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto错误 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoError) |
||||
|
{ |
||||
|
QPlayAuto_OK=0, //成功
|
||||
|
QPlayAuto_QueryAutoFailed=100, //查询车机信息失败
|
||||
|
QPlayAuto_QueryMobileFailed=101, //查询移动设备失败
|
||||
|
QPlayAuto_QuerySongsFailed_WithoutID=102, //查询歌单数据失败,父 ID 不存在
|
||||
|
QPlayAuto_QuerySongsFailed_NoNetwork=103, //查询歌单数据失败,移动设备网络不通,无法下载数据
|
||||
|
QPlayAuto_QuerySongsFailed_Unknow=104, //查询歌单数据失败,原因未知
|
||||
|
QPlayAuto_SongIDError=105, //歌曲 ID 不存在
|
||||
|
QPlayAuto_ReadError=106, //读取数据错误
|
||||
|
QPlayAuto_ParamError=107, //参数错误
|
||||
|
QPlayAuto_SystemError=108, //系统调用错误
|
||||
|
QPlayAuto_CopyRightError=109, //无法播放,没有版权
|
||||
|
QPlayAuto_LoginError=110, //无法读取,没有登录
|
||||
|
QPlayAuto_PcmRepeat=111, //PCM 请求重复
|
||||
|
QPlayAuto_NoPermission=112, //没有权限
|
||||
|
QPlayAuto_NeedBuy = 113, //无法播放(数字专辑)
|
||||
|
QPlayAuto_NotSupportFormat=114, //无法播放(不支持格式)
|
||||
|
QPlayAuto_NeedAuth=115, //需要授权
|
||||
|
QPlayAuto_NeedVIP = 116, //无法播放(需要购买VIP)
|
||||
|
QPlayAuto_TryListen = 117, //试听歌曲,购买听完整版
|
||||
|
QPlayAuto_TrafficAlert = 118, //无法播放(流量弹窗阻断)
|
||||
|
QPlayAuto_OnlyWifi = 119, //无法播放(仅Wifi弹窗阻断)
|
||||
|
QPlayAuto_AlreadyConnected=120, //已经连接车机
|
||||
|
QPlayAuto_SeekError = 121, //拖拽进度错误
|
||||
|
QPlayAuto_NoListenRight = 122, //无法播放(无版权)
|
||||
|
QPlayAuto_SongNotMatch=123, //歌曲不匹配
|
||||
|
QPlayAuto_Disconnect=124, //连接已断开
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto连接状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoConnectState) |
||||
|
{ |
||||
|
QPlayAutoConnectState_Connected = 0, //连接成功
|
||||
|
QPlayAutoConnectState_Disconnect = 1, //断开连接
|
||||
|
QPlayAutoConnectState_Failed = -1, //连接失败
|
||||
|
QPlayAutoConnectState_Cancel = -2, //连接取消
|
||||
|
}; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAutoListItem类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoListItemType) |
||||
|
{ |
||||
|
QPlayAutoListItemType_Song = 1, //歌曲
|
||||
|
QPlayAutoListItemType_Normal = 2, //普通目录
|
||||
|
QPlayAutoListItemType_Radio = 3, //电台
|
||||
|
QPlayAutoListItemType_Folder = 4, //歌单
|
||||
|
QPlayAutoListItemType_Album = 5, //专辑
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoSongListType) |
||||
|
{ |
||||
|
QPlayAutoSongListType_Daily = 108, //每日30首
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayState) |
||||
|
{ |
||||
|
QPlayAutoPlayState_Stop=0, //停止
|
||||
|
QPlayAutoPlayState_Playing=1, //播放
|
||||
|
QPlayAutoPlayState_Pause=2 //暂停
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoAssenceMode) |
||||
|
{ |
||||
|
QPlayAutoAssenceMode_Full = 0, // 默认整首播放
|
||||
|
QPlayAutoAssenceMode_Part = 1, // 仅播放精华片段
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放模式 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayMode) |
||||
|
{ |
||||
|
QPlayAutoPlayMode_SequenceCircle=0, //列表循环
|
||||
|
QPlayAutoPlayMode_SingleCircle=1, //单曲循环
|
||||
|
QPlayAutoPlayMode_RandomCircle=2 //随机播放
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto搜索类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoSearchType) |
||||
|
{ |
||||
|
QPlayAutoSearchType_Song = 0, //歌曲
|
||||
|
QPlayAutoSearchType_Album = 2, //专辑
|
||||
|
QPlayAutoSearchType_Folder = 3, //歌单
|
||||
|
QPlayAutoSearchType_Composite = 100, //综合
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoVipState) |
||||
|
{ |
||||
|
QPlayAutoVipState_Normal = 0, |
||||
|
QPlayAutoVipState_VIP = 1, |
||||
|
QPlayAutoVipState_SVIP = 2, |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
第三方App信息 |
||||
|
*/ |
||||
|
@interface QPlayAutoAppInfo : NSObject<NSCoding> |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *deviceId; //AppId
|
||||
|
@property (nonatomic,assign) NSInteger deviceType; |
||||
|
@property (nonatomic,strong) NSString *scheme; //跳转scheme
|
||||
|
@property (nonatomic,strong) NSString *brand; //品牌
|
||||
|
@property (nonatomic,strong) NSString *name; //名称
|
||||
|
@property (nonatomic,strong) NSString *appId; //名称
|
||||
|
@property (nonatomic,strong) NSString *secretKey; //私钥
|
||||
|
@property (nonatomic,strong) NSString *bundleId; //bundleId
|
||||
|
@property (nonatomic,assign) NSInteger qmCommandPort; //Q音接收命令端口
|
||||
|
@property (nonatomic,strong) NSString *qmHost; //Q音接收命令IP
|
||||
|
@property (nonatomic,strong) NSDate *lastConnectDate;//上次连接的日期
|
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSinger : NSObject |
||||
|
@property (nonatomic,strong) NSString *ID; //ID
|
||||
|
@property (nonatomic,strong) NSString *Mid; //Mid
|
||||
|
@property (nonatomic,strong) NSString *name; //名称
|
||||
|
@end |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto列表项(歌单、电台、排行榜、歌曲、etc) |
||||
|
*/ |
||||
|
@interface QPlayAutoListItem: NSObject |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *ID; //ID
|
||||
|
@property (nonatomic,strong) NSString *Name; //名称
|
||||
|
@property (nonatomic,strong) NSString *SubName; //副标题
|
||||
|
@property (nonatomic,strong) QPlayAutoSinger *singer; //歌手
|
||||
|
@property (nonatomic,strong) NSString *Album; //专辑
|
||||
|
@property (nonatomic,strong) NSString *Mid; |
||||
|
@property (nonatomic,assign) QPlayAutoVipState vipState; |
||||
|
@property (nonatomic,assign) QPlayAutoListItemType Type; |
||||
|
@property (nonatomic,assign) NSInteger Duration; //时长
|
||||
|
@property (nonatomic,strong) NSString *CoverUri; //封面Uri
|
||||
|
@property (nonatomic,assign) NSInteger totalCount; //总数
|
||||
|
@property (nonatomic,assign) BOOL isFav; //是否收藏
|
||||
|
@property (nonatomic,assign) BOOL isOrigin; //是否原唱
|
||||
|
@property (nonatomic,assign) BOOL isNoAudioSource; //无音源
|
||||
|
@property (nonatomic,strong) NSMutableArray<QPlayAutoListItem*> *items; //子列表
|
||||
|
@property (nonatomic,weak) QPlayAutoListItem *parentItem; //父节点
|
||||
|
|
||||
|
@property (nonatomic,assign) BOOL isTryListen; //是否试听歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isSong; //歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isFolder;//歌单
|
||||
|
@property (nonatomic,readonly) BOOL isAlbum; //专辑
|
||||
|
@property (nonatomic,readonly) BOOL isRadio; //电台
|
||||
|
@property (nonatomic,readonly) BOOL isDirectory; //普通目录
|
||||
|
|
||||
|
@property (nonatomic,readonly) BOOL isVIP; //VIP歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isSVIP; //SVIP歌曲
|
||||
|
|
||||
|
- (instancetype)initWithDictionary:(NSDictionary*)dict; |
||||
|
- (instancetype)initSongWithId:(NSString *)identifier isFav:(BOOL)isFav; |
||||
|
- (instancetype)initWithId:(NSString *)identifier type:(QPlayAutoListItemType)type; |
||||
|
|
||||
|
//是否是根节点
|
||||
|
- (BOOL)isRoot; |
||||
|
|
||||
|
//是否有更多
|
||||
|
- (BOOL)hasMore; |
||||
|
|
||||
|
- (QPlayAutoListItem*)findItemWithID:(NSString*)ID; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto请求回调 |
||||
|
|
||||
|
@param success 是否成功 |
||||
|
@param dict 结果Dictionary |
||||
|
*/ |
||||
|
typedef void (^QPlayAutoRequestFinishBlock)(BOOL success, NSDictionary *dict); |
||||
|
|
||||
|
|
||||
|
@interface QPlayAutoRequestBase : NSObject |
||||
|
|
||||
|
/** 请求类型 */ |
||||
|
@property (nonatomic, assign) int type; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSentence : NSObject <NSCoding> |
||||
|
@property (nonatomic, assign) NSInteger startTime; |
||||
|
@property (nonatomic, assign) NSInteger duration; |
||||
|
@property (nonatomic, strong) NSString *text; |
||||
|
@property (nonatomic, readonly) NSString *startTimeText; |
||||
|
@property (nonatomic, readonly) NSString *endTimeText; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoLyric : NSObject <NSCoding> |
||||
|
@property(nonatomic,assign) BOOL isTxtType;//歌词是不是纯文本的歌词,没有时间标记
|
||||
|
@property(nonatomic,strong) NSString *songId; |
||||
|
@property(nonatomic,strong) NSString *songName; |
||||
|
@property(nonatomic,strong) NSString *singerName; |
||||
|
@property(nonatomic,strong) NSString *albumName; |
||||
|
@property(nonatomic,readonly) NSString *text;//所有歌词文本
|
||||
|
@property(nonatomic,strong) NSArray<QPlayAutoSentence *> *sentences; |
||||
|
- (NSString *)sentenceAtTime:(NSTimeInterval)time; |
||||
|
@end |
||||
|
|
||||
|
|
||||
|
#endif /* QPlayAutoDefine_h */ |
||||
@ -0,0 +1,188 @@ |
|||||
|
//
|
||||
|
// QPlayAutoSDK.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/5.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
#import "QPlayAutoDefine.h" |
||||
|
|
||||
|
#define APP_DEVICE_TYPE (3) |
||||
|
|
||||
|
NS_ASSUME_NONNULL_BEGIN |
||||
|
|
||||
|
typedef void (^QPlayAutoResultItemsBlock)(NSInteger errorCode,NSArray<QPlayAutoListItem *> *_Nullable items); |
||||
|
typedef void (^QPlayAutoResultParentItemBlock)(NSInteger errorCode,QPlayAutoListItem *parentItem); |
||||
|
|
||||
|
extern NSString const * QPlayAutoSDKVersion; |
||||
|
|
||||
|
@protocol QPlayAutoSDKDelegate <NSObject> |
||||
|
|
||||
|
//连接状态变化回调
|
||||
|
- (void)onQPlayAutoConnectStateChanged:(QPlayAutoConnectState)newState; |
||||
|
//播放状态状态变化回调
|
||||
|
- (void)onQPlayAutoPlayStateChanged:(QPlayAutoPlayState)playState song:(QPlayAutoListItem *)song position:(NSInteger)position; |
||||
|
//歌曲播放进度
|
||||
|
- (void)onQPlayAutoPlayProgressChanged:(QPlayAutoListItem *)song progress:(NSTimeInterval)progress duration:(NSTimeInterval)duration; |
||||
|
//歌曲收藏状态变化
|
||||
|
- (void)onSongFavoriteStateChange:(NSString*)songID isFavorite:(BOOL)isFavorite; |
||||
|
//播放状态事件变化
|
||||
|
- (void)onPlayModeChange:(QPlayAutoPlayMode)playMode; |
||||
|
//定时关闭事件
|
||||
|
- (void)onPlayPausedByTimeoff; |
||||
|
//登陆状态
|
||||
|
- (void)onLoginStateDidChanged:(BOOL)isLoginOK; |
||||
|
@end |
||||
|
|
||||
|
|
||||
|
|
||||
|
@interface QPlayAutoSDK : NSObject |
||||
|
|
||||
|
/// 注册App
|
||||
|
/// @param name 名称
|
||||
|
/// @param brand 品牌
|
||||
|
/// @param deviceId ?
|
||||
|
/// @param scheme 授权成功后Q音跳转合作方的scheme
|
||||
|
/// @param appId Q音分配的Id
|
||||
|
/// @param secretKey 合作方私钥
|
||||
|
/// @param bundleId 合作方包名
|
||||
|
+ (void)registerAppWithName:(NSString *)name brand:(NSString *)brand deviceId:(NSString *)deviceId scheme:(NSString *)scheme appId:(NSString *)appId secretKey:(NSString *)secretKey bundleId:(NSString *)bundleId; |
||||
|
|
||||
|
/// 播放状态
|
||||
|
+ (QPlayAutoPlayMode)currentPlayMode; |
||||
|
/// 当前歌曲
|
||||
|
+ (QPlayAutoListItem *_Nullable)currentSong; |
||||
|
/// 当前播放状态
|
||||
|
+ (QPlayAutoPlayState)currentPlayState; |
||||
|
/// 当前播放进度
|
||||
|
+ (NSTimeInterval)currentProgress; |
||||
|
/// QQ音乐是否登录
|
||||
|
+ (BOOL)isLoginOK; |
||||
|
/// 检查QQ音乐是否已安装
|
||||
|
+ (BOOL)isQQMusicInstalled; |
||||
|
/// 是否已连接
|
||||
|
+ (BOOL)isConnected; |
||||
|
/// 连接中
|
||||
|
+ (BOOL)isConnecting; |
||||
|
///QQ音乐设备信息
|
||||
|
+ (NSDictionary *)deviceInfo; |
||||
|
|
||||
|
+(NSString *)openId; |
||||
|
+(NSString *)openToken; |
||||
|
|
||||
|
|
||||
|
///是否可以处理回调url
|
||||
|
+ (BOOL)canHandleOpenURL:(NSURL *)url; |
||||
|
///处理回调url
|
||||
|
+ (BOOL)handleOpenURL:(NSURL *)url; |
||||
|
|
||||
|
/// 回调代理
|
||||
|
+ (void)setDelegate:(id<QPlayAutoSDKDelegate>) delegate; |
||||
|
|
||||
|
|
||||
|
/// 拉端连接QPlay
|
||||
|
/// - Parameter forceLogin: 是否强制登录
|
||||
|
+ (void)connectAndForceLogin:(BOOL)forceLogin; |
||||
|
/// 停止
|
||||
|
+ (void)stop; |
||||
|
|
||||
|
|
||||
|
/// 二次热启动连接(需要联系Q音打开此功能才能使用)
|
||||
|
/// - Parameters:
|
||||
|
/// - timeout: 超时时间
|
||||
|
/// - completion: 回调
|
||||
|
+ (void)reconnectWithTimeout:(NSTimeInterval)timeout completion:(QPlayAutoRequestFinishBlock)completion; |
||||
|
|
||||
|
/// 跳转QQ音乐登录
|
||||
|
/// @param bundleId 合作方bundleId
|
||||
|
/// @param callbackUrl 跳转合作方url
|
||||
|
+ (BOOL)loginQQMusicWithBundleId:(NSString *)bundleId callbackUrl:(NSString *)callbackUrl; |
||||
|
|
||||
|
|
||||
|
/// 获取数据
|
||||
|
/// @param parent 父
|
||||
|
/// @param pageIndex 页码
|
||||
|
/// @param pageSize 页大小
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)getDataItemsFromParent:(QPlayAutoListItem *)parent pageIndex:(NSUInteger)pageIndex pageSize:(NSUInteger)pageSize completion:(QPlayAutoResultParentItemBlock)completion; |
||||
|
|
||||
|
|
||||
|
/// 设置播放模式
|
||||
|
/// @param playMode 播放模式
|
||||
|
/// @param block 回调
|
||||
|
+ (NSInteger)setPlayMode:(QPlayAutoPlayMode)playMode callback:(QPlayAutoRequestFinishBlock _Nullable )block; |
||||
|
|
||||
|
|
||||
|
/// 设置播放整首还是高潮
|
||||
|
/// @param assencceMode 高潮还是整首
|
||||
|
/// @param block 回调
|
||||
|
+ (NSInteger)setAssenceMode:(QPlayAutoAssenceMode)assencceMode callback:(QPlayAutoRequestFinishBlock _Nullable )block; |
||||
|
|
||||
|
/// 收藏/取消收藏(歌曲id)
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param isFavorite 收藏/取消收藏
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)setFavoriteStateWithSong:(QPlayAutoListItem *)song isFavorite:(BOOL)isFavorite completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
/// 播放歌曲
|
||||
|
/// @param songList 歌曲列表
|
||||
|
/// @param playIndex 播放索引
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)playAtIndex:(NSArray<QPlayAutoListItem*> *)songList playIndex:(NSInteger)playIndex completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
|
||||
|
/// 通过歌曲Mid列表播放歌曲
|
||||
|
/// @param songMidList 歌曲Mid列表
|
||||
|
/// @param playIndex 播放索引
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)playSongMidAtIndex:(NSArray<NSString*> *)songMidList playIndex:(NSInteger)playIndex completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
|
||||
|
///播放下一首
|
||||
|
+ (void)playerPlayNextWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///播放上一首
|
||||
|
+ (void)playerPlayPrevWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///播放暂停
|
||||
|
+ (void)playerPlayPause; |
||||
|
|
||||
|
///播放恢复
|
||||
|
+ (void)playerPlayResumeWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///Seek到指定位置
|
||||
|
+ (void)playerSeek:(NSInteger)position; |
||||
|
|
||||
|
|
||||
|
/// 搜索歌曲
|
||||
|
/// @param keyword 关键词
|
||||
|
/// @param type 搜索类型
|
||||
|
/// @param firstPage 是否第一页
|
||||
|
/// @param completion 回调
|
||||
|
+ (NSInteger)search:(NSString *)keyword |
||||
|
type:(QPlayAutoSearchType)type |
||||
|
firstPage:(BOOL)firstPage |
||||
|
completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
/// 相似歌曲
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestSimilarWithSong:(QPlayAutoListItem *)song completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
|
||||
|
/// 查询歌词
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestLyricWithSong:(QPlayAutoListItem *)song completion:(void (^)(NSInteger errorCode,QPlayAutoLyric *_Nullable lyric))completion; |
||||
|
|
||||
|
|
||||
|
/// 获取特定歌曲列表
|
||||
|
/// @param type 列表类型
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestSonglistWithType:(QPlayAutoSongListType)type completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
NS_ASSUME_NONNULL_END |
||||
@ -0,0 +1,5 @@ |
|||||
|
framework module QPlayAutoSDK { |
||||
|
umbrella header "QPlayAutoSDK.h" |
||||
|
export * |
||||
|
module * { export * } |
||||
|
} |
||||
Binary file not shown.
@ -0,0 +1,238 @@ |
|||||
|
//
|
||||
|
// QPlayAutoDefine.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/17.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef QPlayAutoDefine_h |
||||
|
#define QPlayAutoDefine_h |
||||
|
|
||||
|
extern NSString *const kQPlayAutoItemRootID; |
||||
|
extern NSString *const kQPlayAutoArgument_Count; |
||||
|
extern NSString *const kQPlayAutoArgument_PageIndex; |
||||
|
extern NSString *const kQPlayAutoArgument_ParentID; |
||||
|
extern NSString *const kQPlayAutoArgument_Lists; |
||||
|
extern NSString *const kQPlayAutoArgument_PlayMode; |
||||
|
extern NSString *const kQPlayAutoArgument_IsFav; |
||||
|
extern NSString *const kQPlayAutoArgument_Position; |
||||
|
extern NSString *const kQPlayAutoArgument_Song; |
||||
|
extern NSString *const kQPlayAutoArgument_SongID; |
||||
|
extern NSString *const kQPlayAutoArgument_State; |
||||
|
extern NSString *const kQPlayAutoArgument_Error; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto错误 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoError) |
||||
|
{ |
||||
|
QPlayAuto_OK=0, //成功
|
||||
|
QPlayAuto_QueryAutoFailed=100, //查询车机信息失败
|
||||
|
QPlayAuto_QueryMobileFailed=101, //查询移动设备失败
|
||||
|
QPlayAuto_QuerySongsFailed_WithoutID=102, //查询歌单数据失败,父 ID 不存在
|
||||
|
QPlayAuto_QuerySongsFailed_NoNetwork=103, //查询歌单数据失败,移动设备网络不通,无法下载数据
|
||||
|
QPlayAuto_QuerySongsFailed_Unknow=104, //查询歌单数据失败,原因未知
|
||||
|
QPlayAuto_SongIDError=105, //歌曲 ID 不存在
|
||||
|
QPlayAuto_ReadError=106, //读取数据错误
|
||||
|
QPlayAuto_ParamError=107, //参数错误
|
||||
|
QPlayAuto_SystemError=108, //系统调用错误
|
||||
|
QPlayAuto_CopyRightError=109, //无法播放,没有版权
|
||||
|
QPlayAuto_LoginError=110, //无法读取,没有登录
|
||||
|
QPlayAuto_PcmRepeat=111, //PCM 请求重复
|
||||
|
QPlayAuto_NoPermission=112, //没有权限
|
||||
|
QPlayAuto_NeedBuy = 113, //无法播放(数字专辑)
|
||||
|
QPlayAuto_NotSupportFormat=114, //无法播放(不支持格式)
|
||||
|
QPlayAuto_NeedAuth=115, //需要授权
|
||||
|
QPlayAuto_NeedVIP = 116, //无法播放(需要购买VIP)
|
||||
|
QPlayAuto_TryListen = 117, //试听歌曲,购买听完整版
|
||||
|
QPlayAuto_TrafficAlert = 118, //无法播放(流量弹窗阻断)
|
||||
|
QPlayAuto_OnlyWifi = 119, //无法播放(仅Wifi弹窗阻断)
|
||||
|
QPlayAuto_AlreadyConnected=120, //已经连接车机
|
||||
|
QPlayAuto_SeekError = 121, //拖拽进度错误
|
||||
|
QPlayAuto_NoListenRight = 122, //无法播放(无版权)
|
||||
|
QPlayAuto_SongNotMatch=123, //歌曲不匹配
|
||||
|
QPlayAuto_Disconnect=124, //连接已断开
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto连接状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoConnectState) |
||||
|
{ |
||||
|
QPlayAutoConnectState_Connected = 0, //连接成功
|
||||
|
QPlayAutoConnectState_Disconnect = 1, //断开连接
|
||||
|
QPlayAutoConnectState_Failed = -1, //连接失败
|
||||
|
QPlayAutoConnectState_Cancel = -2, //连接取消
|
||||
|
}; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAutoListItem类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoListItemType) |
||||
|
{ |
||||
|
QPlayAutoListItemType_Song = 1, //歌曲
|
||||
|
QPlayAutoListItemType_Normal = 2, //普通目录
|
||||
|
QPlayAutoListItemType_Radio = 3, //电台
|
||||
|
QPlayAutoListItemType_Folder = 4, //歌单
|
||||
|
QPlayAutoListItemType_Album = 5, //专辑
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoSongListType) |
||||
|
{ |
||||
|
QPlayAutoSongListType_Daily = 108, //每日30首
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayState) |
||||
|
{ |
||||
|
QPlayAutoPlayState_Stop=0, //停止
|
||||
|
QPlayAutoPlayState_Playing=1, //播放
|
||||
|
QPlayAutoPlayState_Pause=2 //暂停
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoAssenceMode) |
||||
|
{ |
||||
|
QPlayAutoAssenceMode_Full = 0, // 默认整首播放
|
||||
|
QPlayAutoAssenceMode_Part = 1, // 仅播放精华片段
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放模式 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayMode) |
||||
|
{ |
||||
|
QPlayAutoPlayMode_SequenceCircle=0, //列表循环
|
||||
|
QPlayAutoPlayMode_SingleCircle=1, //单曲循环
|
||||
|
QPlayAutoPlayMode_RandomCircle=2 //随机播放
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto搜索类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoSearchType) |
||||
|
{ |
||||
|
QPlayAutoSearchType_Song = 0, //歌曲
|
||||
|
QPlayAutoSearchType_Album = 2, //专辑
|
||||
|
QPlayAutoSearchType_Folder = 3, //歌单
|
||||
|
QPlayAutoSearchType_Composite = 100, //综合
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoVipState) |
||||
|
{ |
||||
|
QPlayAutoVipState_Normal = 0, |
||||
|
QPlayAutoVipState_VIP = 1, |
||||
|
QPlayAutoVipState_SVIP = 2, |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
第三方App信息 |
||||
|
*/ |
||||
|
@interface QPlayAutoAppInfo : NSObject<NSCoding> |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *deviceId; //AppId
|
||||
|
@property (nonatomic,assign) NSInteger deviceType; |
||||
|
@property (nonatomic,strong) NSString *scheme; //跳转scheme
|
||||
|
@property (nonatomic,strong) NSString *brand; //品牌
|
||||
|
@property (nonatomic,strong) NSString *name; //名称
|
||||
|
@property (nonatomic,strong) NSString *appId; //名称
|
||||
|
@property (nonatomic,strong) NSString *secretKey; //私钥
|
||||
|
@property (nonatomic,strong) NSString *bundleId; //bundleId
|
||||
|
@property (nonatomic,assign) NSInteger qmCommandPort; //Q音接收命令端口
|
||||
|
@property (nonatomic,strong) NSString *qmHost; //Q音接收命令IP
|
||||
|
@property (nonatomic,strong) NSDate *lastConnectDate;//上次连接的日期
|
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSinger : NSObject |
||||
|
@property (nonatomic,strong) NSString *ID; //ID
|
||||
|
@property (nonatomic,strong) NSString *Mid; //Mid
|
||||
|
@property (nonatomic,strong) NSString *name; //名称
|
||||
|
@end |
||||
|
|
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto列表项(歌单、电台、排行榜、歌曲、etc) |
||||
|
*/ |
||||
|
@interface QPlayAutoListItem: NSObject |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *ID; //ID
|
||||
|
@property (nonatomic,strong) NSString *Name; //名称
|
||||
|
@property (nonatomic,strong) NSString *SubName; //副标题
|
||||
|
@property (nonatomic,strong) QPlayAutoSinger *singer; //歌手
|
||||
|
@property (nonatomic,strong) NSString *Album; //专辑
|
||||
|
@property (nonatomic,strong) NSString *Mid; |
||||
|
@property (nonatomic,assign) QPlayAutoVipState vipState; |
||||
|
@property (nonatomic,assign) QPlayAutoListItemType Type; |
||||
|
@property (nonatomic,assign) NSInteger Duration; //时长
|
||||
|
@property (nonatomic,strong) NSString *CoverUri; //封面Uri
|
||||
|
@property (nonatomic,assign) NSInteger totalCount; //总数
|
||||
|
@property (nonatomic,assign) BOOL isFav; //是否收藏
|
||||
|
@property (nonatomic,assign) BOOL isOrigin; //是否原唱
|
||||
|
@property (nonatomic,assign) BOOL isNoAudioSource; //无音源
|
||||
|
@property (nonatomic,strong) NSMutableArray<QPlayAutoListItem*> *items; //子列表
|
||||
|
@property (nonatomic,weak) QPlayAutoListItem *parentItem; //父节点
|
||||
|
|
||||
|
@property (nonatomic,assign) BOOL isTryListen; //是否试听歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isSong; //歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isFolder;//歌单
|
||||
|
@property (nonatomic,readonly) BOOL isAlbum; //专辑
|
||||
|
@property (nonatomic,readonly) BOOL isRadio; //电台
|
||||
|
@property (nonatomic,readonly) BOOL isDirectory; //普通目录
|
||||
|
|
||||
|
@property (nonatomic,readonly) BOOL isVIP; //VIP歌曲
|
||||
|
@property (nonatomic,readonly) BOOL isSVIP; //SVIP歌曲
|
||||
|
|
||||
|
- (instancetype)initWithDictionary:(NSDictionary*)dict; |
||||
|
- (instancetype)initSongWithId:(NSString *)identifier isFav:(BOOL)isFav; |
||||
|
- (instancetype)initWithId:(NSString *)identifier type:(QPlayAutoListItemType)type; |
||||
|
|
||||
|
//是否是根节点
|
||||
|
- (BOOL)isRoot; |
||||
|
|
||||
|
//是否有更多
|
||||
|
- (BOOL)hasMore; |
||||
|
|
||||
|
- (QPlayAutoListItem*)findItemWithID:(NSString*)ID; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto请求回调 |
||||
|
|
||||
|
@param success 是否成功 |
||||
|
@param dict 结果Dictionary |
||||
|
*/ |
||||
|
typedef void (^QPlayAutoRequestFinishBlock)(BOOL success, NSDictionary *dict); |
||||
|
|
||||
|
|
||||
|
@interface QPlayAutoRequestBase : NSObject |
||||
|
|
||||
|
/** 请求类型 */ |
||||
|
@property (nonatomic, assign) int type; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSentence : NSObject <NSCoding> |
||||
|
@property (nonatomic, assign) NSInteger startTime; |
||||
|
@property (nonatomic, assign) NSInteger duration; |
||||
|
@property (nonatomic, strong) NSString *text; |
||||
|
@property (nonatomic, readonly) NSString *startTimeText; |
||||
|
@property (nonatomic, readonly) NSString *endTimeText; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoLyric : NSObject <NSCoding> |
||||
|
@property(nonatomic,assign) BOOL isTxtType;//歌词是不是纯文本的歌词,没有时间标记
|
||||
|
@property(nonatomic,strong) NSString *songId; |
||||
|
@property(nonatomic,strong) NSString *songName; |
||||
|
@property(nonatomic,strong) NSString *singerName; |
||||
|
@property(nonatomic,strong) NSString *albumName; |
||||
|
@property(nonatomic,readonly) NSString *text;//所有歌词文本
|
||||
|
@property(nonatomic,strong) NSArray<QPlayAutoSentence *> *sentences; |
||||
|
- (NSString *)sentenceAtTime:(NSTimeInterval)time; |
||||
|
@end |
||||
|
|
||||
|
|
||||
|
#endif /* QPlayAutoDefine_h */ |
||||
@ -0,0 +1,188 @@ |
|||||
|
//
|
||||
|
// QPlayAutoSDK.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/5.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
#import "QPlayAutoDefine.h" |
||||
|
|
||||
|
#define APP_DEVICE_TYPE (3) |
||||
|
|
||||
|
NS_ASSUME_NONNULL_BEGIN |
||||
|
|
||||
|
typedef void (^QPlayAutoResultItemsBlock)(NSInteger errorCode,NSArray<QPlayAutoListItem *> *_Nullable items); |
||||
|
typedef void (^QPlayAutoResultParentItemBlock)(NSInteger errorCode,QPlayAutoListItem *parentItem); |
||||
|
|
||||
|
extern NSString const * QPlayAutoSDKVersion; |
||||
|
|
||||
|
@protocol QPlayAutoSDKDelegate <NSObject> |
||||
|
|
||||
|
//连接状态变化回调
|
||||
|
- (void)onQPlayAutoConnectStateChanged:(QPlayAutoConnectState)newState; |
||||
|
//播放状态状态变化回调
|
||||
|
- (void)onQPlayAutoPlayStateChanged:(QPlayAutoPlayState)playState song:(QPlayAutoListItem *)song position:(NSInteger)position; |
||||
|
//歌曲播放进度
|
||||
|
- (void)onQPlayAutoPlayProgressChanged:(QPlayAutoListItem *)song progress:(NSTimeInterval)progress duration:(NSTimeInterval)duration; |
||||
|
//歌曲收藏状态变化
|
||||
|
- (void)onSongFavoriteStateChange:(NSString*)songID isFavorite:(BOOL)isFavorite; |
||||
|
//播放状态事件变化
|
||||
|
- (void)onPlayModeChange:(QPlayAutoPlayMode)playMode; |
||||
|
//定时关闭事件
|
||||
|
- (void)onPlayPausedByTimeoff; |
||||
|
//登陆状态
|
||||
|
- (void)onLoginStateDidChanged:(BOOL)isLoginOK; |
||||
|
@end |
||||
|
|
||||
|
|
||||
|
|
||||
|
@interface QPlayAutoSDK : NSObject |
||||
|
|
||||
|
/// 注册App
|
||||
|
/// @param name 名称
|
||||
|
/// @param brand 品牌
|
||||
|
/// @param deviceId ?
|
||||
|
/// @param scheme 授权成功后Q音跳转合作方的scheme
|
||||
|
/// @param appId Q音分配的Id
|
||||
|
/// @param secretKey 合作方私钥
|
||||
|
/// @param bundleId 合作方包名
|
||||
|
+ (void)registerAppWithName:(NSString *)name brand:(NSString *)brand deviceId:(NSString *)deviceId scheme:(NSString *)scheme appId:(NSString *)appId secretKey:(NSString *)secretKey bundleId:(NSString *)bundleId; |
||||
|
|
||||
|
/// 播放状态
|
||||
|
+ (QPlayAutoPlayMode)currentPlayMode; |
||||
|
/// 当前歌曲
|
||||
|
+ (QPlayAutoListItem *_Nullable)currentSong; |
||||
|
/// 当前播放状态
|
||||
|
+ (QPlayAutoPlayState)currentPlayState; |
||||
|
/// 当前播放进度
|
||||
|
+ (NSTimeInterval)currentProgress; |
||||
|
/// QQ音乐是否登录
|
||||
|
+ (BOOL)isLoginOK; |
||||
|
/// 检查QQ音乐是否已安装
|
||||
|
+ (BOOL)isQQMusicInstalled; |
||||
|
/// 是否已连接
|
||||
|
+ (BOOL)isConnected; |
||||
|
/// 连接中
|
||||
|
+ (BOOL)isConnecting; |
||||
|
///QQ音乐设备信息
|
||||
|
+ (NSDictionary *)deviceInfo; |
||||
|
|
||||
|
+(NSString *)openId; |
||||
|
+(NSString *)openToken; |
||||
|
|
||||
|
|
||||
|
///是否可以处理回调url
|
||||
|
+ (BOOL)canHandleOpenURL:(NSURL *)url; |
||||
|
///处理回调url
|
||||
|
+ (BOOL)handleOpenURL:(NSURL *)url; |
||||
|
|
||||
|
/// 回调代理
|
||||
|
+ (void)setDelegate:(id<QPlayAutoSDKDelegate>) delegate; |
||||
|
|
||||
|
|
||||
|
/// 拉端连接QPlay
|
||||
|
/// - Parameter forceLogin: 是否强制登录
|
||||
|
+ (void)connectAndForceLogin:(BOOL)forceLogin; |
||||
|
/// 停止
|
||||
|
+ (void)stop; |
||||
|
|
||||
|
|
||||
|
/// 二次热启动连接(需要联系Q音打开此功能才能使用)
|
||||
|
/// - Parameters:
|
||||
|
/// - timeout: 超时时间
|
||||
|
/// - completion: 回调
|
||||
|
+ (void)reconnectWithTimeout:(NSTimeInterval)timeout completion:(QPlayAutoRequestFinishBlock)completion; |
||||
|
|
||||
|
/// 跳转QQ音乐登录
|
||||
|
/// @param bundleId 合作方bundleId
|
||||
|
/// @param callbackUrl 跳转合作方url
|
||||
|
+ (BOOL)loginQQMusicWithBundleId:(NSString *)bundleId callbackUrl:(NSString *)callbackUrl; |
||||
|
|
||||
|
|
||||
|
/// 获取数据
|
||||
|
/// @param parent 父
|
||||
|
/// @param pageIndex 页码
|
||||
|
/// @param pageSize 页大小
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)getDataItemsFromParent:(QPlayAutoListItem *)parent pageIndex:(NSUInteger)pageIndex pageSize:(NSUInteger)pageSize completion:(QPlayAutoResultParentItemBlock)completion; |
||||
|
|
||||
|
|
||||
|
/// 设置播放模式
|
||||
|
/// @param playMode 播放模式
|
||||
|
/// @param block 回调
|
||||
|
+ (NSInteger)setPlayMode:(QPlayAutoPlayMode)playMode callback:(QPlayAutoRequestFinishBlock _Nullable )block; |
||||
|
|
||||
|
|
||||
|
/// 设置播放整首还是高潮
|
||||
|
/// @param assencceMode 高潮还是整首
|
||||
|
/// @param block 回调
|
||||
|
+ (NSInteger)setAssenceMode:(QPlayAutoAssenceMode)assencceMode callback:(QPlayAutoRequestFinishBlock _Nullable )block; |
||||
|
|
||||
|
/// 收藏/取消收藏(歌曲id)
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param isFavorite 收藏/取消收藏
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)setFavoriteStateWithSong:(QPlayAutoListItem *)song isFavorite:(BOOL)isFavorite completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
/// 播放歌曲
|
||||
|
/// @param songList 歌曲列表
|
||||
|
/// @param playIndex 播放索引
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)playAtIndex:(NSArray<QPlayAutoListItem*> *)songList playIndex:(NSInteger)playIndex completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
|
||||
|
/// 通过歌曲Mid列表播放歌曲
|
||||
|
/// @param songMidList 歌曲Mid列表
|
||||
|
/// @param playIndex 播放索引
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)playSongMidAtIndex:(NSArray<NSString*> *)songMidList playIndex:(NSInteger)playIndex completion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
|
||||
|
///播放下一首
|
||||
|
+ (void)playerPlayNextWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///播放上一首
|
||||
|
+ (void)playerPlayPrevWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///播放暂停
|
||||
|
+ (void)playerPlayPause; |
||||
|
|
||||
|
///播放恢复
|
||||
|
+ (void)playerPlayResumeWithCompletion:(void (^)(NSInteger errorCode))completion; |
||||
|
|
||||
|
///Seek到指定位置
|
||||
|
+ (void)playerSeek:(NSInteger)position; |
||||
|
|
||||
|
|
||||
|
/// 搜索歌曲
|
||||
|
/// @param keyword 关键词
|
||||
|
/// @param type 搜索类型
|
||||
|
/// @param firstPage 是否第一页
|
||||
|
/// @param completion 回调
|
||||
|
+ (NSInteger)search:(NSString *)keyword |
||||
|
type:(QPlayAutoSearchType)type |
||||
|
firstPage:(BOOL)firstPage |
||||
|
completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
/// 相似歌曲
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestSimilarWithSong:(QPlayAutoListItem *)song completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
|
||||
|
/// 查询歌词
|
||||
|
/// @param song 歌曲
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestLyricWithSong:(QPlayAutoListItem *)song completion:(void (^)(NSInteger errorCode,QPlayAutoLyric *_Nullable lyric))completion; |
||||
|
|
||||
|
|
||||
|
/// 获取特定歌曲列表
|
||||
|
/// @param type 列表类型
|
||||
|
/// @param completion 回调
|
||||
|
+ (void)requestSonglistWithType:(QPlayAutoSongListType)type completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
NS_ASSUME_NONNULL_END |
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,8 @@ |
|||||
|
module QPlayAutoSDK { |
||||
|
header "Headers/include/QPlayAutoSDK.h" |
||||
|
header "Headers/include/QPlayAutoDefine.h" |
||||
|
|
||||
|
export * |
||||
|
|
||||
|
link "QPlayAutoSDK" |
||||
|
} |
||||
@ -1,32 +1,26 @@ |
|||||
// swift-tools-version: 5.9 |
// swift-tools-version: 5.7 |
||||
// The swift-tools-version declares the minimum version of Swift required to build this package. |
|
||||
|
|
||||
import PackageDescription |
import PackageDescription |
||||
|
|
||||
let package = Package( |
let package = Package( |
||||
name: "qq_music", |
name: "qq_music", |
||||
platforms: [ |
platforms: [ |
||||
.iOS("12.0") |
.iOS(.v11) |
||||
], |
], |
||||
products: [ |
products: [ |
||||
.library(name: "qq-music", targets: ["qq_music"]) |
.library( |
||||
|
name: "qq-music", |
||||
|
targets: ["qq_music"] |
||||
|
), |
||||
], |
], |
||||
dependencies: [], |
|
||||
targets: [ |
targets: [ |
||||
.target( |
.target( |
||||
name: "qq_music", |
name: "qq_music", |
||||
dependencies: [], |
dependencies: ["QPlayAutoSDK"], |
||||
resources: [ |
path: "Sources/qq_music" |
||||
// If your plugin requires a privacy manifest, for example if it uses any required |
), |
||||
// reason APIs, update the PrivacyInfo.xcprivacy file to describe your plugin's |
.binaryTarget( |
||||
// privacy impact, and then uncomment these lines. For more information, see |
name: "QPlayAutoSDK", |
||||
// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files |
path: "Frameworks/QPlayAutoSDK.xcframework" |
||||
// .process("PrivacyInfo.xcprivacy"), |
|
||||
|
|
||||
// If you have other resources that need to be bundled with your plugin, refer to |
|
||||
// the following instructions to add them: |
|
||||
// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package |
|
||||
] |
|
||||
) |
) |
||||
] |
] |
||||
) |
) |
||||
@ -1,14 +0,0 @@ |
|||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|
||||
<plist version="1.0"> |
|
||||
<dict> |
|
||||
<key>NSPrivacyTrackingDomains</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyAccessedAPITypes</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyCollectedDataTypes</key> |
|
||||
<array/> |
|
||||
<key>NSPrivacyTracking</key> |
|
||||
<false/> |
|
||||
</dict> |
|
||||
</plist> |
|
||||
@ -0,0 +1,261 @@ |
|||||
|
import Foundation |
||||
|
import UIKit |
||||
|
import QPlayAutoSDK |
||||
|
|
||||
|
@objc public class QPlayAutoManager: NSObject { |
||||
|
|
||||
|
@objc public static let shared = QPlayAutoManager() |
||||
|
|
||||
|
private var delegates: [WeakDelegate] = [] |
||||
|
|
||||
|
private override init() { |
||||
|
super.init() |
||||
|
QPlayAutoSDK.setDelegate(self) |
||||
|
} |
||||
|
|
||||
|
// MARK: - Delegate Management |
||||
|
@objc public func addDelegate(_ delegate: QPlayAutoManagerDelegate) { |
||||
|
delegates.append(WeakDelegate(delegate)) |
||||
|
cleanupDelegates() |
||||
|
} |
||||
|
|
||||
|
@objc public func removeDelegate(_ delegate: QPlayAutoManagerDelegate) { |
||||
|
delegates.removeAll { $0.delegate === delegate } |
||||
|
} |
||||
|
|
||||
|
private func cleanupDelegates() { |
||||
|
delegates.removeAll { $0.delegate == nil } |
||||
|
} |
||||
|
|
||||
|
// MARK: - App Registration |
||||
|
@objc public func registerApp( |
||||
|
name: String, |
||||
|
brand: String, |
||||
|
deviceId: String, |
||||
|
scheme: String, |
||||
|
appId: String, |
||||
|
secretKey: String, |
||||
|
bundleId: String |
||||
|
) { |
||||
|
QPlayAutoSDK.registerApp( |
||||
|
withName: name, |
||||
|
brand: brand, |
||||
|
deviceId: deviceId, |
||||
|
scheme: scheme, |
||||
|
appId: appId, |
||||
|
secretKey: secretKey, |
||||
|
bundleId: bundleId |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
// MARK: - Connection Management |
||||
|
@objc public func connect(forceLogin: Bool = false) { |
||||
|
QPlayAutoSDK.connectAndForceLogin(forceLogin) |
||||
|
} |
||||
|
|
||||
|
@objc public func reconnect(timeout: TimeInterval, completion: @escaping (Bool, [String: Any]?) -> Void) { |
||||
|
QPlayAutoSDK.reconnect(withTimeout: timeout) { (success, dict) in |
||||
|
// 修复:直接使用Bool类型,不进行Int比较 |
||||
|
completion(success, dict as? [String: Any]) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func stop() { |
||||
|
QPlayAutoSDK.stop() |
||||
|
} |
||||
|
|
||||
|
// MARK: - 播放控制 |
||||
|
@objc public func play() { |
||||
|
// 使用新的方法名 |
||||
|
QPlayAutoSDK.playerPlayResume { errorCode in |
||||
|
print("Resume play result: \(errorCode)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func play(songId: String) { |
||||
|
// 播放特定歌曲需要先搜索或使用歌曲列表 |
||||
|
// 这里提供一个简化的实现 |
||||
|
QPlayAutoSDK.playerPlayResume { errorCode in |
||||
|
print("Play song result: \(errorCode)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func pause() { |
||||
|
QPlayAutoSDK.playerPlayPause() |
||||
|
} |
||||
|
|
||||
|
@objc public func next() { |
||||
|
QPlayAutoSDK.playerPlayNext { errorCode in |
||||
|
print("Next song result: \(errorCode)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func previous() { |
||||
|
QPlayAutoSDK.playerPlayPrev { errorCode in |
||||
|
print("Previous song result: \(errorCode)") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func seek(to position: TimeInterval) { |
||||
|
QPlayAutoSDK.playerSeek(Int(position)) |
||||
|
} |
||||
|
|
||||
|
// MARK: - 状态查询 |
||||
|
@objc public var isConnected: Bool { |
||||
|
return QPlayAutoSDK.isConnected() |
||||
|
} |
||||
|
|
||||
|
@objc public var isConnecting: Bool { |
||||
|
return QPlayAutoSDK.isConnecting() |
||||
|
} |
||||
|
|
||||
|
@objc public var currentSong: QPlayAutoListItem? { |
||||
|
return QPlayAutoSDK.currentSong() |
||||
|
} |
||||
|
|
||||
|
@objc public var currentPlayState: QPlayAutoPlayState { |
||||
|
return QPlayAutoSDK.currentPlayState() |
||||
|
} |
||||
|
|
||||
|
@objc public var currentPlayMode: QPlayAutoPlayMode { |
||||
|
return QPlayAutoSDK.currentPlayMode() |
||||
|
} |
||||
|
|
||||
|
@objc public var currentProgress: Int { |
||||
|
return Int(QPlayAutoSDK.currentProgress()) |
||||
|
} |
||||
|
|
||||
|
@objc public var isLoginOK: Bool { |
||||
|
return QPlayAutoSDK.isLoginOK() |
||||
|
} |
||||
|
|
||||
|
@objc public var isQQMusicInstalled: Bool { |
||||
|
return QPlayAutoSDK.isQQMusicInstalled() |
||||
|
} |
||||
|
|
||||
|
@objc public var deviceInfo: [String: Any] { |
||||
|
return QPlayAutoSDK.deviceInfo() as? [String: Any] ?? [:] |
||||
|
} |
||||
|
|
||||
|
// Add missing properties |
||||
|
@objc public var openId: String? { |
||||
|
return QPlayAutoSDK.openId() |
||||
|
} |
||||
|
|
||||
|
@objc public var openToken: String? { |
||||
|
return QPlayAutoSDK.openToken() |
||||
|
} |
||||
|
|
||||
|
// MARK: - URL Handling |
||||
|
@objc public func canHandleOpenURL(url: String) -> Bool { |
||||
|
guard let nsurl = URL(string: url) else { return false } |
||||
|
return QPlayAutoSDK.canHandleOpen(nsurl) |
||||
|
} |
||||
|
|
||||
|
@objc public func handleOpenURL(_ url: URL) -> Bool { |
||||
|
return QPlayAutoSDK.handleOpen(url) |
||||
|
} |
||||
|
|
||||
|
// MARK: - Search and Content |
||||
|
@objc public func search( |
||||
|
keyword: String, |
||||
|
searchType: QPlayAutoSearchType, |
||||
|
completion: @escaping ([QPlayAutoListItem]?) -> Void |
||||
|
) { |
||||
|
QPlayAutoSDK.search(keyword, type: searchType, firstPage: true) { (error, items) in |
||||
|
completion(items) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@objc public func getItems( |
||||
|
playlistId: String, |
||||
|
completion: @escaping ([QPlayAutoListItem]?) -> Void |
||||
|
) { |
||||
|
// Create a QPlayAutoListItem object |
||||
|
// with the playlistId to use as parentItem |
||||
|
let parentItem = QPlayAutoListItem() |
||||
|
parentItem.id = playlistId |
||||
|
|
||||
|
QPlayAutoSDK.getDataItems(fromParent: parentItem, pageIndex: 0, pageSize: 50) { (error, items) in |
||||
|
// 修复:确保items是正确的类型 |
||||
|
if error == 0 { |
||||
|
completion(items as? [QPlayAutoListItem]) |
||||
|
} else { |
||||
|
completion(nil) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - QPlayAutoSDKDelegate |
||||
|
extension QPlayAutoManager: QPlayAutoSDKDelegate { |
||||
|
|
||||
|
public func onQPlayAutoConnectStateChanged(_ newState: QPlayAutoConnectState) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onConnectStateChanged?(newState) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onQPlayAutoPlayStateChanged(_ playState: QPlayAutoPlayState, song: QPlayAutoListItem, position: Int) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onPlayStateChanged?(playState, song: song, position: position) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onQPlayAutoPlayProgressChanged(_ song: QPlayAutoListItem, progress: TimeInterval, duration: TimeInterval) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onPlayProgressChanged?(song, progress: progress, duration: duration) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onSongFavoriteStateChange(_ songID: String, isFavorite: Bool) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onSongFavoriteStateChange?(songID, isFavorite: isFavorite) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onPlayModeChange(_ playMode: QPlayAutoPlayMode) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onPlayModeChange?(playMode) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onPlayPausedByTimeoff() { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onPlayPausedByTimeoff?() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public func onLoginStateDidChanged(_ isLoginOK: Bool) { |
||||
|
cleanupDelegates() |
||||
|
for weakDelegate in delegates { |
||||
|
weakDelegate.delegate?.onLoginStateDidChanged?(isLoginOK) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - Delegate Protocol |
||||
|
@objc public protocol QPlayAutoManagerDelegate: AnyObject { |
||||
|
@objc optional func onConnectStateChanged(_ newState: QPlayAutoConnectState) |
||||
|
@objc optional func onPlayStateChanged(_ playState: QPlayAutoPlayState, song: QPlayAutoListItem, position: Int) |
||||
|
@objc optional func onPlayProgressChanged(_ song: QPlayAutoListItem, progress: TimeInterval, duration: TimeInterval) |
||||
|
@objc optional func onSongFavoriteStateChange(_ songID: String, isFavorite: Bool) |
||||
|
@objc optional func onPlayModeChange(_ playMode: QPlayAutoPlayMode) |
||||
|
@objc optional func onPlayPausedByTimeoff() |
||||
|
@objc optional func onLoginStateDidChanged(_ isLoginOK: Bool) |
||||
|
} |
||||
|
|
||||
|
// MARK: - Helper Classes |
||||
|
private class WeakDelegate { |
||||
|
weak var delegate: QPlayAutoManagerDelegate? |
||||
|
|
||||
|
init(_ delegate: QPlayAutoManagerDelegate) { |
||||
|
self.delegate = delegate |
||||
|
} |
||||
|
} |
||||
@ -1,19 +1,472 @@ |
|||||
import Flutter |
import Flutter |
||||
import UIKit |
import UIKit |
||||
|
import QPlayAutoSDK |
||||
|
|
||||
public class QqMusicPlugin: NSObject, FlutterPlugin { |
public class QqMusicPlugin: NSObject, FlutterPlugin { |
||||
|
private var methodChannel: FlutterMethodChannel? |
||||
|
private var eventChannel: FlutterEventChannel? |
||||
|
private var eventSink: FlutterEventSink? |
||||
|
|
||||
public static func register(with registrar: FlutterPluginRegistrar) { |
public static func register(with registrar: FlutterPluginRegistrar) { |
||||
let channel = FlutterMethodChannel(name: "qq_music", binaryMessenger: registrar.messenger()) |
let channel = FlutterMethodChannel(name: "qq_music", binaryMessenger: registrar.messenger()) |
||||
let instance = QqMusicPlugin() |
let instance = QqMusicPlugin() |
||||
|
instance.methodChannel = channel |
||||
registrar.addMethodCallDelegate(instance, channel: channel) |
registrar.addMethodCallDelegate(instance, channel: channel) |
||||
|
|
||||
|
// 设置事件通道 |
||||
|
let eventChannel = FlutterEventChannel(name: "qq_music_events", binaryMessenger: registrar.messenger()) |
||||
|
instance.eventChannel = eventChannel |
||||
|
eventChannel.setStreamHandler(instance) |
||||
|
|
||||
|
// 设置代理 |
||||
|
QPlayAutoManager.shared.addDelegate(instance) |
||||
} |
} |
||||
|
|
||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
switch call.method { |
switch call.method { |
||||
|
case "registerApp": |
||||
|
handleRegisterApp(call, result: result) |
||||
|
case "connect": |
||||
|
handleConnect(call, result: result) |
||||
|
case "reconnect": |
||||
|
handleReconnect(call, result: result) |
||||
|
case "stop": |
||||
|
handleStop(call, result: result) |
||||
|
case "login": |
||||
|
handleLogin(call, result: result) |
||||
|
case "searchSongs": |
||||
|
handleSearchSongs(call, result: result) |
||||
|
case "playSongs": |
||||
|
handlePlaySongs(call, result: result) |
||||
|
case "play": |
||||
|
handlePlay(call, result: result) |
||||
|
case "playMusic": |
||||
|
handlePlayMusic(call, result: result) |
||||
|
case "pause": |
||||
|
handlePause(call, result: result) |
||||
|
case "pauseMusic": |
||||
|
handlePauseMusic(call, result: result) |
||||
|
case "resumeMusic": |
||||
|
handleResumeMusic(call, result: result) |
||||
|
case "stopMusic": |
||||
|
handleStopMusic(call, result: result) |
||||
|
case "next": |
||||
|
handleNext(call, result: result) |
||||
|
case "skipToNext": |
||||
|
handleSkipToNext(call, result: result) |
||||
|
case "previous": |
||||
|
handlePrevious(call, result: result) |
||||
|
case "skipToPrevious": |
||||
|
handleSkipToPrevious(call, result: result) |
||||
|
case "seek": |
||||
|
handleSeek(call, result: result) |
||||
|
case "isConnected": |
||||
|
result(QPlayAutoManager.shared.isConnected) |
||||
|
case "isConnecting": |
||||
|
result(QPlayAutoManager.shared.isConnecting) |
||||
|
case "currentSong": |
||||
|
handleCurrentSong(result: result) |
||||
|
case "getCurrentSong": |
||||
|
handleGetCurrentSong(result: result) |
||||
|
case "currentPlayState": |
||||
|
result(QPlayAutoManager.shared.currentPlayState.rawValue) |
||||
|
case "getPlaybackState": |
||||
|
handleGetPlaybackState(result: result) |
||||
|
case "currentPlayMode": |
||||
|
result(QPlayAutoManager.shared.currentPlayMode.rawValue) |
||||
|
case "currentProgress": |
||||
|
result(QPlayAutoManager.shared.currentProgress) |
||||
|
case "getPlayTime": |
||||
|
handleGetPlayTime(result: result) |
||||
|
case "isLoginOK": |
||||
|
result(QPlayAutoManager.shared.isLoginOK) |
||||
|
case "isQQMusicInstalled": |
||||
|
result(QPlayAutoManager.shared.isQQMusicInstalled) |
||||
|
case "openUrl": |
||||
|
handleOpenUrl(call, result: result) |
||||
|
case "search": |
||||
|
handleSearch(call, result: result) |
||||
|
case "getPlaylistContent": |
||||
|
handleGetPlaylistContent(call, result: result) |
||||
|
case "syncCurrentPlayInfo": |
||||
|
handleSyncCurrentPlayInfo(result: result) |
||||
case "getPlatformVersion": |
case "getPlatformVersion": |
||||
result("iOS " + UIDevice.current.systemVersion) |
handleGetPlatformVersion(result: result) |
||||
default: |
default: |
||||
result(FlutterMethodNotImplemented) |
result(FlutterMethodNotImplemented) |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
// MARK: - Method Handlers |
||||
|
|
||||
|
private func handleRegisterApp(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let name = args["name"] as? String, |
||||
|
let brand = args["brand"] as? String, |
||||
|
let deviceId = args["deviceId"] as? String, |
||||
|
let scheme = args["scheme"] as? String, |
||||
|
let appId = args["appId"] as? String, |
||||
|
let secretKey = args["secretKey"] as? String, |
||||
|
let bundleId = args["bundleId"] as? String else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing required parameters", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
QPlayAutoManager.shared.registerApp( |
||||
|
name: name, |
||||
|
brand: brand, |
||||
|
deviceId: deviceId, |
||||
|
scheme: scheme, |
||||
|
appId: appId, |
||||
|
secretKey: secretKey, |
||||
|
bundleId: bundleId |
||||
|
) |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleConnect(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
let forceLogin = (call.arguments as? [String: Any])?["forceLogin"] as? Bool ?? false |
||||
|
QPlayAutoManager.shared.connect(forceLogin: forceLogin) |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleReconnect(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let timeout = args["timeout"] as? Double else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing timeout", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
QPlayAutoManager.shared.reconnect(timeout: timeout) { success, dict in |
||||
|
result(["success": success, "data": dict ?? [:]]) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private func handleStop(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.stop() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
// 新增:登录功能 |
||||
|
private func handleLogin(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
let isLoginOK = QPlayAutoManager.shared.isLoginOK |
||||
|
if isLoginOK { |
||||
|
let openId = QPlayAutoManager.shared.openId ?? "" |
||||
|
let openToken = QPlayAutoManager.shared.openToken ?? "" |
||||
|
result([ |
||||
|
"success": true, |
||||
|
"openId": openId, |
||||
|
"openToken": openToken, |
||||
|
"expireTime": "" |
||||
|
]) |
||||
|
} else { |
||||
|
result(FlutterError(code: "LOGIN_FAILED", message: "User not logged in", details: nil)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 新增:搜索歌曲功能 |
||||
|
private func handleSearchSongs(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let keyword = args["keyword"] as? String else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing keyword", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
let searchType = args["searchType"] as? Int ?? 0 |
||||
|
|
||||
|
QPlayAutoManager.shared.search(keyword: keyword, searchType: QPlayAutoSearchType(rawValue: searchType) ?? .song) { items in |
||||
|
if let items = items { |
||||
|
let songs = items.map { item -> [String: Any] in |
||||
|
return [ |
||||
|
"id": item.id ?? "", |
||||
|
"name": item.name ?? "", |
||||
|
"artist": item.singer?.name ?? "", |
||||
|
"album": item.album ?? "", |
||||
|
"duration": item.duration, |
||||
|
"mid": item.id ?? "" |
||||
|
] |
||||
|
} |
||||
|
result(["success": true, "songs": songs]) |
||||
|
} else { |
||||
|
result(FlutterError(code: "SEARCH_FAILED", message: "Search failed", details: nil)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 新增:播放歌曲列表功能 |
||||
|
private func handlePlaySongs(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let songMids = args["songMids"] as? [String], |
||||
|
!songMids.isEmpty else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENT", message: "songMids is required", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
let index = args["index"] as? Int ?? 0 |
||||
|
|
||||
|
if index < songMids.count { |
||||
|
let songId = songMids[index] |
||||
|
QPlayAutoManager.shared.play(songId: songId) |
||||
|
result(["success": true]) |
||||
|
} else { |
||||
|
result(FlutterError(code: "PLAY_FAILED", message: "Invalid index", details: nil)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private func handlePlay(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
if let args = call.arguments as? [String: Any], |
||||
|
let songId = args["songId"] as? String { |
||||
|
QPlayAutoManager.shared.play(songId: songId) |
||||
|
} else { |
||||
|
QPlayAutoManager.shared.play() |
||||
|
} |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handlePlayMusic(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.play() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handlePause(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.pause() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handlePauseMusic(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.pause() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleResumeMusic(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.play() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleStopMusic(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.stop() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleNext(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.next() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleSkipToNext(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.next() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handlePrevious(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.previous() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleSkipToPrevious(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
QPlayAutoManager.shared.previous() |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
private func handleSeek(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let position = args["position"] as? Int else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing position", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
QPlayAutoManager.shared.seek(to: TimeInterval(position)) |
||||
|
result(["success": true]) |
||||
|
} |
||||
|
|
||||
|
// 第286-290行 - handleCurrentSong方法 |
||||
|
private func handleCurrentSong(result: @escaping FlutterResult) { |
||||
|
if let song = QPlayAutoManager.shared.currentSong { |
||||
|
let songInfo: [String: Any] = [ |
||||
|
"id": song.id ?? "", |
||||
|
"name": song.name ?? "", |
||||
|
"artist": song.singer?.name ?? "", |
||||
|
"album": song.album ?? "", |
||||
|
"duration": song.duration |
||||
|
] |
||||
|
result(songInfo) |
||||
|
} else { |
||||
|
result(nil) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第302-307行 - handleGetCurrentSong方法 |
||||
|
private func handleGetCurrentSong(result: @escaping FlutterResult) { |
||||
|
if let song = QPlayAutoManager.shared.currentSong { |
||||
|
let songInfo: [String: Any] = [ |
||||
|
"id": song.id ?? "", |
||||
|
"name": song.name ?? "", |
||||
|
"artist": song.singer?.name ?? "", |
||||
|
"album": song.album ?? "", |
||||
|
"duration": song.duration, |
||||
|
"mid": song.id ?? "" |
||||
|
] |
||||
|
result(["success": true, "data": songInfo]) |
||||
|
} else { |
||||
|
result(FlutterError(code: "NO_CURRENT_SONG", message: "No current song", details: nil)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第323行 - handleGetPlayTime方法 |
||||
|
private func handleGetPlayTime(result: @escaping FlutterResult) { |
||||
|
if let currentSong = QPlayAutoManager.shared.currentSong { |
||||
|
let playTime: [String: Any] = [ |
||||
|
"currentTime": QPlayAutoManager.shared.currentProgress, |
||||
|
"duration": currentSong.duration |
||||
|
] |
||||
|
result(playTime) |
||||
|
} else { |
||||
|
result(nil) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private func handleGetPlaybackState(result: @escaping FlutterResult) { |
||||
|
let playbackState: [String: Any] = [ |
||||
|
"state": QPlayAutoManager.shared.currentPlayState.rawValue, |
||||
|
"position": QPlayAutoManager.shared.currentProgress |
||||
|
] |
||||
|
result(["success": true, "data": playbackState]) |
||||
|
} |
||||
|
|
||||
|
private func handleOpenUrl(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let urlString = args["url"] as? String else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing url parameter", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if QPlayAutoManager.shared.canHandleOpenURL(url: urlString), |
||||
|
let url = URL(string: urlString) { |
||||
|
let handled = QPlayAutoManager.shared.handleOpenURL(url) |
||||
|
result(["success": handled]) |
||||
|
} else { |
||||
|
result(["success": false]) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第357-361行 - handleSearch方法中的映射 |
||||
|
private func handleSearch(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let keyword = args["keyword"] as? String else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing keyword", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
let searchType = args["searchType"] as? Int ?? 0 |
||||
|
|
||||
|
QPlayAutoManager.shared.search(keyword: keyword, searchType: QPlayAutoSearchType(rawValue: searchType) ?? .song) { items in |
||||
|
if let items = items { |
||||
|
let songs = items.map { item -> [String: Any] in |
||||
|
return [ |
||||
|
"id": item.id ?? "", |
||||
|
"name": item.name ?? "", |
||||
|
"artist": item.singer?.name ?? "", |
||||
|
"album": item.album ?? "", |
||||
|
"duration": item.duration |
||||
|
] |
||||
|
} |
||||
|
result(["success": true, "songs": songs]) |
||||
|
} else { |
||||
|
result(["success": false, "songs": []]) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第382-386行 - handleGetPlaylistContent方法中的映射 |
||||
|
private func handleGetPlaylistContent(_ call: FlutterMethodCall, result: @escaping FlutterResult) { |
||||
|
guard let args = call.arguments as? [String: Any], |
||||
|
let playlistId = args["playlistId"] as? String else { |
||||
|
result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing playlistId", details: nil)) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
QPlayAutoManager.shared.getItems(playlistId: playlistId) { items in |
||||
|
if let items = items { |
||||
|
let songs = items.map { item -> [String: Any] in |
||||
|
return [ |
||||
|
"id": item.id ?? "", |
||||
|
"name": item.name ?? "", |
||||
|
"artist": item.singer?.name ?? "", |
||||
|
"album": item.album ?? "", |
||||
|
"duration": item.duration |
||||
|
] |
||||
|
} |
||||
|
result(["success": true, "songs": songs]) |
||||
|
} else { |
||||
|
result(["success": false, "songs": []]) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第405-409行 - handleSyncCurrentPlayInfo方法 |
||||
|
private func handleSyncCurrentPlayInfo(result: @escaping FlutterResult) { |
||||
|
if let song = QPlayAutoManager.shared.currentSong { |
||||
|
let playInfo: [String: Any] = [ |
||||
|
"id": song.id ?? "", |
||||
|
"name": song.name ?? "", |
||||
|
"artist": song.singer?.name ?? "", |
||||
|
"album": song.album ?? "", |
||||
|
"duration": song.duration |
||||
|
] |
||||
|
result(["success": true, "data": playInfo]) |
||||
|
} else { |
||||
|
result(FlutterError(code: "NO_CURRENT_SONG", message: "No current song playing", details: nil)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 第492-496行 - 重复的handleGetPlaylistContent方法(需要删除) |
||||
|
// 删除这个重复的方法声明 |
||||
|
|
||||
|
// 第509-513行 - 重复的handleSyncCurrentPlayInfo方法(需要删除) |
||||
|
// 删除这个重复的方法声明 |
||||
|
|
||||
|
private func handleGetPlatformVersion(result: @escaping FlutterResult) { |
||||
|
let version = "iOS " + UIDevice.current.systemVersion |
||||
|
result(version) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - FlutterStreamHandler |
||||
|
extension QqMusicPlugin: FlutterStreamHandler { |
||||
|
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { |
||||
|
self.eventSink = events |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
public func onCancel(withArguments arguments: Any?) -> FlutterError? { |
||||
|
self.eventSink = nil |
||||
|
return nil |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - QPlayAutoManagerDelegate |
||||
|
extension QqMusicPlugin: QPlayAutoManagerDelegate { |
||||
|
public func onConnectStateChanged(_ state: QPlayAutoConnectState) { |
||||
|
eventSink?(["type": "connectStateChanged", "state": state.rawValue]) |
||||
|
} |
||||
|
|
||||
|
public func onPlayStateChanged(_ state: QPlayAutoPlayState, song: QPlayAutoListItem, position: Int) { |
||||
|
eventSink?(["type": "playStateChanged", "state": state.rawValue]) |
||||
|
} |
||||
|
|
||||
|
public func onPlayProgressChanged(_ song: QPlayAutoListItem, progress: TimeInterval, duration: TimeInterval) { |
||||
|
eventSink?(["type": "progressChanged", "progress": Int(progress)]) |
||||
|
} |
||||
|
|
||||
|
public func onSongFavoriteStateChange(_ songID: String, isFavorite: Bool) { |
||||
|
eventSink?(["type": "favoriteStateChanged", "songId": songID, "isFavorite": isFavorite]) |
||||
|
} |
||||
|
|
||||
|
public func onPlayModeChange(_ mode: QPlayAutoPlayMode) { |
||||
|
eventSink?(["type": "playModeChanged", "mode": mode.rawValue]) |
||||
|
} |
||||
|
|
||||
|
public func onLoginStateDidChanged(_ isLogin: Bool) { |
||||
|
eventSink?(["type": "loginStateChanged", "isLogin": isLogin]) |
||||
|
} |
||||
} |
} |
||||
@ -0,0 +1,213 @@ |
|||||
|
//
|
||||
|
// QPlayAutoDefine.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/17.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef QPlayAutoDefine_h |
||||
|
#define QPlayAutoDefine_h |
||||
|
|
||||
|
extern NSString *const kQPlayAutoItemRootID; |
||||
|
extern NSString *const kQPlayAutoArgument_Count; |
||||
|
extern NSString *const kQPlayAutoArgument_PageIndex; |
||||
|
extern NSString *const kQPlayAutoArgument_ParentID; |
||||
|
extern NSString *const kQPlayAutoArgument_Lists; |
||||
|
extern NSString *const kQPlayAutoArgument_PlayMode; |
||||
|
extern NSString *const kQPlayAutoArgument_IsFav; |
||||
|
extern NSString *const kQPlayAutoArgument_Position; |
||||
|
extern NSString *const kQPlayAutoArgument_Song; |
||||
|
extern NSString *const kQPlayAutoArgument_SongID; |
||||
|
extern NSString *const kQPlayAutoArgument_State; |
||||
|
extern NSString *const kQPlayAutoArgument_Error; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto错误 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoError) |
||||
|
{ |
||||
|
QPlayAuto_OK=0, //成功
|
||||
|
QPlayAuto_QueryAutoFailed=100, //查询车机信息失败
|
||||
|
QPlayAuto_QueryMobileFailed=101, //查询移动设备失败
|
||||
|
QPlayAuto_QuerySongsFailed_WithoutID=102, //查询歌单数据失败,父 ID 不存在
|
||||
|
QPlayAuto_QuerySongsFailed_NoNetwork=103, //查询歌单数据失败,移动设备网络不通,无法下载数据
|
||||
|
QPlayAuto_QuerySongsFailed_Unknow=104, //查询歌单数据失败,原因未知
|
||||
|
QPlayAuto_SongIDError=105, //歌曲 ID 不存在
|
||||
|
QPlayAuto_ReadError=106, //读取数据错误
|
||||
|
QPlayAuto_ParamError=107, //参数错误
|
||||
|
QPlayAuto_SystemError=108, //系统调用错误
|
||||
|
QPlayAuto_CopyRightError=109, //无法播放,没有版权
|
||||
|
QPlayAuto_LoginError=110, //无法读取,没有登录
|
||||
|
QPlayAuto_PcmRepeat=111, //PCM 请求重复
|
||||
|
QPlayAuto_NoPermission=112, //没有权限
|
||||
|
QPlayAuto_NeedBuy = 113, //无法播放(数字专辑)
|
||||
|
QPlayAuto_NotSupportFormat=114, //无法播放(不支持格式)
|
||||
|
QPlayAuto_NeedAuth=115, //需要授权
|
||||
|
QPlayAuto_NeedVIP = 116, //无法播放(需要购买VIP)
|
||||
|
QPlayAuto_TryListen = 117, //试听歌曲,购买听完整版
|
||||
|
QPlayAuto_TrafficAlert = 118, //无法播放(流量弹窗阻断)
|
||||
|
QPlayAuto_OnlyWifi = 119, //无法播放(仅Wifi弹窗阻断)
|
||||
|
QPlayAuto_AlreadyConnected=120, //已经连接车机
|
||||
|
QPlayAuto_SeekError = 121, //拖拽进度错误
|
||||
|
QPlayAuto_NoListenRight = 122, //无法播放(无版权)
|
||||
|
QPlayAuto_SongNotMatch=123, //歌曲不匹配
|
||||
|
QPlayAuto_Disconnect=124, //连接已断开
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto连接状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoConnectState) |
||||
|
{ |
||||
|
QPlayAutoConnectState_Connected = 0, //连接成功
|
||||
|
QPlayAutoConnectState_Disconnect = 1, //断开连接
|
||||
|
QPlayAutoConnectState_Failed = -1, //连接失败
|
||||
|
QPlayAutoConnectState_Cancel = -2, //连接取消
|
||||
|
}; |
||||
|
|
||||
|
/*
|
||||
|
QPlayAutoListItem类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoListItemType) |
||||
|
{ |
||||
|
QPlayAutoListItemType_Song = 1, //歌曲
|
||||
|
QPlayAutoListItemType_Normal = 2, //普通目录
|
||||
|
QPlayAutoListItemType_Radio = 3, //电台
|
||||
|
QPlayAutoListItemType_Folder = 4, //歌单
|
||||
|
QPlayAutoListItemType_Album = 5, //专辑
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放状态 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayState) |
||||
|
{ |
||||
|
QPlayAutoPlayState_Stop=0, //停止
|
||||
|
QPlayAutoPlayState_Playing=1, //播放
|
||||
|
QPlayAutoPlayState_Pause=2 //暂停
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto播放模式 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSUInteger, QPlayAutoPlayMode) |
||||
|
{ |
||||
|
QPlayAutoPlayMode_SequenceCircle=0, //列表循环
|
||||
|
QPlayAutoPlayMode_SingleCircle=1, //单曲循环
|
||||
|
QPlayAutoPlayMode_RandomCircle=2 //随机播放
|
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto搜索类型 |
||||
|
*/ |
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoSearchType) |
||||
|
{ |
||||
|
QPlayAutoSearchType_Song = 0, //歌曲
|
||||
|
QPlayAutoSearchType_Album = 2, //专辑
|
||||
|
QPlayAutoSearchType_Folder = 3, //歌单
|
||||
|
QPlayAutoSearchType_Composite = 100, //综合
|
||||
|
}; |
||||
|
|
||||
|
typedef NS_ENUM(NSInteger, QPlayAutoVipState) |
||||
|
{ |
||||
|
QPlayAutoVipState_Normal = 0, |
||||
|
QPlayAutoVipState_VIP = 1, |
||||
|
QPlayAutoVipState_SVIP = 2, |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
第三方App信息 |
||||
|
*/ |
||||
|
@interface QPlayAutoAppInfo : NSObject<NSCoding> |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *deviceId; |
||||
|
@property (nonatomic,assign) NSInteger deviceType; |
||||
|
@property (nonatomic,strong) NSString *scheme; |
||||
|
@property (nonatomic,strong) NSString *brand; |
||||
|
@property (nonatomic,strong) NSString *name; |
||||
|
@property (nonatomic,strong) NSString *appId; |
||||
|
@property (nonatomic,strong) NSString *secretKey; |
||||
|
@property (nonatomic,strong) NSString *bundleId; |
||||
|
@property (nonatomic,assign) NSInteger qmCommandPort; |
||||
|
@property (nonatomic,strong) NSString *qmHost; |
||||
|
@property (nonatomic,strong) NSDate *lastConnectDate; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSinger : NSObject |
||||
|
@property (nonatomic,strong) NSString *ID; |
||||
|
@property (nonatomic,strong) NSString *Mid; |
||||
|
@property (nonatomic,strong) NSString *name; |
||||
|
@end |
||||
|
|
||||
|
/*
|
||||
|
QPlayAuto列表项(歌单、电台、排行榜、歌曲、etc) |
||||
|
*/ |
||||
|
@interface QPlayAutoListItem: NSObject |
||||
|
|
||||
|
@property (nonatomic,strong) NSString *ID; |
||||
|
@property (nonatomic,strong) NSString *Name; |
||||
|
@property (nonatomic,strong) NSString *SubName; |
||||
|
@property (nonatomic,strong) QPlayAutoSinger *singer; |
||||
|
@property (nonatomic,strong) NSString *Album; |
||||
|
@property (nonatomic,strong) NSString *Mid; |
||||
|
@property (nonatomic,assign) QPlayAutoVipState vipState; |
||||
|
@property (nonatomic,assign) QPlayAutoListItemType Type; |
||||
|
@property (nonatomic,assign) NSInteger Duration; |
||||
|
@property (nonatomic,strong) NSString *CoverUri; |
||||
|
@property (nonatomic,assign) NSInteger totalCount; |
||||
|
@property (nonatomic,assign) BOOL isFav; |
||||
|
@property (nonatomic,assign) BOOL isOrigin; |
||||
|
@property (nonatomic,assign) BOOL isNoAudioSource; |
||||
|
@property (nonatomic,strong) NSMutableArray<QPlayAutoListItem*> *items; |
||||
|
@property (nonatomic,weak) QPlayAutoListItem *parentItem; |
||||
|
|
||||
|
@property (nonatomic,assign) BOOL isTryListen; |
||||
|
@property (nonatomic,readonly) BOOL isSong; |
||||
|
@property (nonatomic,readonly) BOOL isFolder; |
||||
|
@property (nonatomic,readonly) BOOL isAlbum; |
||||
|
@property (nonatomic,readonly) BOOL isRadio; |
||||
|
@property (nonatomic,readonly) BOOL isDirectory; |
||||
|
|
||||
|
@property (nonatomic,readonly) BOOL isVIP; |
||||
|
@property (nonatomic,readonly) BOOL isSVIP; |
||||
|
|
||||
|
- (instancetype)initWithDictionary:(NSDictionary*)dict; |
||||
|
- (instancetype)initSongWithId:(NSString *)identifier isFav:(BOOL)isFav; |
||||
|
- (instancetype)initWithId:(NSString *)identifier type:(QPlayAutoListItemType)type; |
||||
|
|
||||
|
- (BOOL)isRoot; |
||||
|
- (BOOL)hasMore; |
||||
|
- (QPlayAutoListItem*)findItemWithID:(NSString*)ID; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
/**
|
||||
|
QPlayAuto请求回调 |
||||
|
*/ |
||||
|
typedef void (^QPlayAutoRequestFinishBlock)(BOOL success, NSDictionary *dict); |
||||
|
|
||||
|
@interface QPlayAutoRequestBase : NSObject |
||||
|
@property (nonatomic, assign) int type; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSentence : NSObject <NSCoding> |
||||
|
@property (nonatomic, assign) NSInteger startTime; |
||||
|
@property (nonatomic, assign) NSInteger duration; |
||||
|
@property (nonatomic, strong) NSString *text; |
||||
|
@property (nonatomic, readonly) NSString *startTimeText; |
||||
|
@property (nonatomic, readonly) NSString *endTimeText; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoLyric : NSObject <NSCoding> |
||||
|
@property(nonatomic,assign) BOOL isTxtType; |
||||
|
@property(nonatomic,strong) NSString *songId; |
||||
|
@property(nonatomic,strong) NSString *songName; |
||||
|
@property(nonatomic,strong) NSString *singerName; |
||||
|
@property(nonatomic,strong) NSString *albumName; |
||||
|
@property(nonatomic,readonly) NSString *text; |
||||
|
@property(nonatomic,strong) NSArray<QPlayAutoSentence *> *sentences; |
||||
|
- (NSString *)sentenceAtTime:(NSTimeInterval)time; |
||||
|
@end |
||||
|
|
||||
|
#endif /* QPlayAutoDefine_h */ |
||||
@ -0,0 +1,97 @@ |
|||||
|
//
|
||||
|
// QPlayAutoSDK.h
|
||||
|
// QPlayAutoSDK
|
||||
|
//
|
||||
|
// Created by travisli(李鞠佑) on 2018/11/5.
|
||||
|
// Copyright © 2018年 腾讯音乐. All rights reserved.
|
||||
|
//
|
||||
|
|
||||
|
#import <Foundation/Foundation.h> |
||||
|
#import "QPlayAutoDefine.h" |
||||
|
|
||||
|
#define APP_DEVICE_TYPE (3) |
||||
|
|
||||
|
NS_ASSUME_NONNULL_BEGIN |
||||
|
|
||||
|
typedef void (^QPlayAutoResultItemsBlock)(NSInteger errorCode,NSArray<QPlayAutoListItem *> *_Nullable items); |
||||
|
typedef void (^QPlayAutoResultParentItemBlock)(NSInteger errorCode,QPlayAutoListItem *parentItem); |
||||
|
|
||||
|
extern NSString const * QPlayAutoSDKVersion; |
||||
|
|
||||
|
@protocol QPlayAutoSDKDelegate <NSObject> |
||||
|
|
||||
|
//连接状态变化回调
|
||||
|
- (void)onQPlayAutoConnectStateChanged:(QPlayAutoConnectState)newState; |
||||
|
//播放状态状态变化回调
|
||||
|
- (void)onQPlayAutoPlayStateChanged:(QPlayAutoPlayState)playState song:(QPlayAutoListItem *)song position:(NSInteger)position; |
||||
|
//歌曲播放进度
|
||||
|
- (void)onQPlayAutoPlayProgressChanged:(QPlayAutoListItem *)song progress:(NSTimeInterval)progress duration:(NSTimeInterval)duration; |
||||
|
//歌曲收藏状态变化
|
||||
|
- (void)onSongFavoriteStateChange:(NSString*)songID isFavorite:(BOOL)isFavorite; |
||||
|
//播放状态事件变化
|
||||
|
- (void)onPlayModeChange:(QPlayAutoPlayMode)playMode; |
||||
|
//定时关闭事件
|
||||
|
- (void)onPlayPausedByTimeoff; |
||||
|
//登陆状态
|
||||
|
- (void)onLoginStateDidChanged:(BOOL)isLoginOK; |
||||
|
@end |
||||
|
|
||||
|
@interface QPlayAutoSDK : NSObject |
||||
|
|
||||
|
/// 注册App
|
||||
|
+ (void)registerAppWithName:(NSString *)name brand:(NSString *)brand deviceId:(NSString *)deviceId scheme:(NSString *)scheme appId:(NSString *)appId secretKey:(NSString *)secretKey bundleId:(NSString *)bundleId; |
||||
|
|
||||
|
/// 播放状态
|
||||
|
+ (QPlayAutoPlayMode)currentPlayMode; |
||||
|
/// 当前歌曲
|
||||
|
+ (QPlayAutoListItem *_Nullable)currentSong; |
||||
|
/// 当前播放状态
|
||||
|
+ (QPlayAutoPlayState)currentPlayState; |
||||
|
/// 当前播放进度
|
||||
|
+ (NSTimeInterval)currentProgress; |
||||
|
/// QQ音乐是否登录
|
||||
|
+ (BOOL)isLoginOK; |
||||
|
/// 检查QQ音乐是否已安装
|
||||
|
+ (BOOL)isQQMusicInstalled; |
||||
|
/// 是否已连接
|
||||
|
+ (BOOL)isConnected; |
||||
|
/// 连接中
|
||||
|
+ (BOOL)isConnecting; |
||||
|
///QQ音乐设备信息
|
||||
|
+ (NSDictionary *)deviceInfo; |
||||
|
|
||||
|
+(NSString *)openId; |
||||
|
+(NSString *)openToken; |
||||
|
|
||||
|
///是否可以处理回调url
|
||||
|
+ (BOOL)canHandleOpenURL:(NSURL *)url; |
||||
|
///处理回调url
|
||||
|
+ (BOOL)handleOpenURL:(NSURL *)url; |
||||
|
|
||||
|
/// 回调代理
|
||||
|
+ (void)setDelegate:(id<QPlayAutoSDKDelegate>) delegate; |
||||
|
|
||||
|
/// 拉端连接QPlay
|
||||
|
+ (void)connectAndForceLogin:(BOOL)forceLogin; |
||||
|
/// 停止
|
||||
|
+ (void)stop; |
||||
|
|
||||
|
/// 二次热启动连接
|
||||
|
+ (void)reconnectWithTimeout:(NSTimeInterval)timeout completion:(QPlayAutoRequestFinishBlock)completion; |
||||
|
|
||||
|
/// 播放控制
|
||||
|
+ (void)play; |
||||
|
+ (void)pause; |
||||
|
+ (void)next; |
||||
|
+ (void)previous; |
||||
|
+ (void)seekToTime:(NSTimeInterval)time; |
||||
|
|
||||
|
/// 搜索
|
||||
|
+ (void)searchWithKeyword:(NSString *)keyword type:(QPlayAutoSearchType)type pageIndex:(NSInteger)pageIndex completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
/// 获取歌单内容
|
||||
|
+ (void)getItemsWithParentItem:(QPlayAutoListItem *)parentItem pageIndex:(NSInteger)pageIndex completion:(QPlayAutoResultItemsBlock)completion; |
||||
|
|
||||
|
@end |
||||
|
|
||||
|
NS_ASSUME_NONNULL_END |
||||
@ -0,0 +1,5 @@ |
|||||
|
module QPlayAutoSDK { |
||||
|
header "QPlayAutoSDK.h" |
||||
|
header "QPlayAutoDefine.h" |
||||
|
export * |
||||
|
} |
||||
Loading…
Reference in new issue