Sfoglia il codice sorgente

1.添加DFPlayer 作为音频播放器

huangxiaodong 1 anno fa
parent
commit
51aacfb91a
17 ha cambiato i file con 3523 aggiunte e 0 eliminazioni
  1. 112 0
      创维盒子/双子星云手机.xcodeproj/project.pbxproj
  2. 338 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayer.h
  3. 862 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayer.m
  4. 45 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerModel.h
  5. 18 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerModel.m
  6. 202 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerUIManager.h
  7. 387 0
      创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerUIManager.m
  8. 64 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerFileManager.h
  9. 155 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerFileManager.m
  10. 43 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerLyricsTableview.h
  11. 634 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerLyricsTableview.m
  12. 66 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerRequestManager.h
  13. 196 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerRequestManager.m
  14. 42 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerResourceLoader.h
  15. 156 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerResourceLoader.m
  16. 75 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerTool.h
  17. 128 0
      创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerTool.m

+ 112 - 0
创维盒子/双子星云手机.xcodeproj/project.pbxproj

@@ -275,6 +275,38 @@
 		6B467BBA2BC7F7D70039A6A6 /* fileUploadToFileCenterModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B467BB72BC7F7D70039A6A6 /* fileUploadToFileCenterModel.m */; };
 		6B467BBB2BC7F7D70039A6A6 /* fileUploadToFileCenterModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B467BB62BC7F7D70039A6A6 /* fileUploadToFileCenterModel.h */; };
 		6B4835FD2B9172D7001FC9BA /* usbInsertAnimation.json in Resources */ = {isa = PBXBuildFile; fileRef = 6B4835FC2B9172D7001FC9BA /* usbInsertAnimation.json */; };
+		6B4C0F622C0314BA0070EF2E /* DFPlayerFileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F4C2C0314BA0070EF2E /* DFPlayerFileManager.h */; };
+		6B4C0F632C0314BA0070EF2E /* DFPlayerFileManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F4C2C0314BA0070EF2E /* DFPlayerFileManager.h */; };
+		6B4C0F642C0314BA0070EF2E /* DFPlayerFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F4D2C0314BA0070EF2E /* DFPlayerFileManager.m */; };
+		6B4C0F652C0314BA0070EF2E /* DFPlayerFileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F4D2C0314BA0070EF2E /* DFPlayerFileManager.m */; };
+		6B4C0F662C0314BA0070EF2E /* DFPlayerLyricsTableview.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F4E2C0314BA0070EF2E /* DFPlayerLyricsTableview.h */; };
+		6B4C0F672C0314BA0070EF2E /* DFPlayerLyricsTableview.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F4E2C0314BA0070EF2E /* DFPlayerLyricsTableview.h */; };
+		6B4C0F682C0314BA0070EF2E /* DFPlayerLyricsTableview.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F4F2C0314BA0070EF2E /* DFPlayerLyricsTableview.m */; };
+		6B4C0F692C0314BA0070EF2E /* DFPlayerLyricsTableview.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F4F2C0314BA0070EF2E /* DFPlayerLyricsTableview.m */; };
+		6B4C0F6A2C0314BA0070EF2E /* DFPlayerRequestManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F502C0314BA0070EF2E /* DFPlayerRequestManager.h */; };
+		6B4C0F6B2C0314BA0070EF2E /* DFPlayerRequestManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F502C0314BA0070EF2E /* DFPlayerRequestManager.h */; };
+		6B4C0F6C2C0314BA0070EF2E /* DFPlayerRequestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F512C0314BA0070EF2E /* DFPlayerRequestManager.m */; };
+		6B4C0F6D2C0314BA0070EF2E /* DFPlayerRequestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F512C0314BA0070EF2E /* DFPlayerRequestManager.m */; };
+		6B4C0F6E2C0314BA0070EF2E /* DFPlayerResourceLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F522C0314BA0070EF2E /* DFPlayerResourceLoader.h */; };
+		6B4C0F6F2C0314BA0070EF2E /* DFPlayerResourceLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F522C0314BA0070EF2E /* DFPlayerResourceLoader.h */; };
+		6B4C0F702C0314BA0070EF2E /* DFPlayerResourceLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F532C0314BA0070EF2E /* DFPlayerResourceLoader.m */; };
+		6B4C0F712C0314BA0070EF2E /* DFPlayerResourceLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F532C0314BA0070EF2E /* DFPlayerResourceLoader.m */; };
+		6B4C0F722C0314BA0070EF2E /* DFPlayerTool.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F542C0314BA0070EF2E /* DFPlayerTool.h */; };
+		6B4C0F732C0314BA0070EF2E /* DFPlayerTool.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F542C0314BA0070EF2E /* DFPlayerTool.h */; };
+		6B4C0F742C0314BA0070EF2E /* DFPlayerTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F552C0314BA0070EF2E /* DFPlayerTool.m */; };
+		6B4C0F752C0314BA0070EF2E /* DFPlayerTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F552C0314BA0070EF2E /* DFPlayerTool.m */; };
+		6B4C0F762C0314BA0070EF2E /* DFPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F572C0314BA0070EF2E /* DFPlayer.h */; };
+		6B4C0F772C0314BA0070EF2E /* DFPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F572C0314BA0070EF2E /* DFPlayer.h */; };
+		6B4C0F782C0314BA0070EF2E /* DFPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F582C0314BA0070EF2E /* DFPlayer.m */; };
+		6B4C0F792C0314BA0070EF2E /* DFPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F582C0314BA0070EF2E /* DFPlayer.m */; };
+		6B4C0F7A2C0314BA0070EF2E /* DFPlayerModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F592C0314BA0070EF2E /* DFPlayerModel.h */; };
+		6B4C0F7B2C0314BA0070EF2E /* DFPlayerModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F592C0314BA0070EF2E /* DFPlayerModel.h */; };
+		6B4C0F7C2C0314BA0070EF2E /* DFPlayerModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F5A2C0314BA0070EF2E /* DFPlayerModel.m */; };
+		6B4C0F7D2C0314BA0070EF2E /* DFPlayerModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F5A2C0314BA0070EF2E /* DFPlayerModel.m */; };
+		6B4C0F7E2C0314BA0070EF2E /* DFPlayerUIManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F5B2C0314BA0070EF2E /* DFPlayerUIManager.h */; };
+		6B4C0F7F2C0314BA0070EF2E /* DFPlayerUIManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4C0F5B2C0314BA0070EF2E /* DFPlayerUIManager.h */; };
+		6B4C0F802C0314BA0070EF2E /* DFPlayerUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F5C2C0314BA0070EF2E /* DFPlayerUIManager.m */; };
+		6B4C0F812C0314BA0070EF2E /* DFPlayerUIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4C0F5C2C0314BA0070EF2E /* DFPlayerUIManager.m */; };
 		6B4D23B12B33DDBC005B718A /* imageVersionRenewTipView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B4D23AF2B33DDBB005B718A /* imageVersionRenewTipView.h */; };
 		6B4D23B22B33DDBC005B718A /* imageVersionRenewTipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B4D23B02B33DDBB005B718A /* imageVersionRenewTipView.m */; };
 		6B5B60602B3BC8DE009A2AE2 /* fileTransferPopView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B5B605E2B3BC8DE009A2AE2 /* fileTransferPopView.h */; };
@@ -1287,6 +1319,22 @@
 		6B4835FC2B9172D7001FC9BA /* usbInsertAnimation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = usbInsertAnimation.json; sourceTree = "<group>"; };
 		6B4B0B692BEF087E00B62C22 /* 隐私保护.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "隐私保护.entitlements"; sourceTree = "<group>"; };
 		6B4B0B6A2BEF16F200B62C22 /* 计算器.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "计算器.entitlements"; sourceTree = "<group>"; };
+		6B4C0F4C2C0314BA0070EF2E /* DFPlayerFileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerFileManager.h; sourceTree = "<group>"; };
+		6B4C0F4D2C0314BA0070EF2E /* DFPlayerFileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerFileManager.m; sourceTree = "<group>"; };
+		6B4C0F4E2C0314BA0070EF2E /* DFPlayerLyricsTableview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerLyricsTableview.h; sourceTree = "<group>"; };
+		6B4C0F4F2C0314BA0070EF2E /* DFPlayerLyricsTableview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerLyricsTableview.m; sourceTree = "<group>"; };
+		6B4C0F502C0314BA0070EF2E /* DFPlayerRequestManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerRequestManager.h; sourceTree = "<group>"; };
+		6B4C0F512C0314BA0070EF2E /* DFPlayerRequestManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerRequestManager.m; sourceTree = "<group>"; };
+		6B4C0F522C0314BA0070EF2E /* DFPlayerResourceLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerResourceLoader.h; sourceTree = "<group>"; };
+		6B4C0F532C0314BA0070EF2E /* DFPlayerResourceLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerResourceLoader.m; sourceTree = "<group>"; };
+		6B4C0F542C0314BA0070EF2E /* DFPlayerTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerTool.h; sourceTree = "<group>"; };
+		6B4C0F552C0314BA0070EF2E /* DFPlayerTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerTool.m; sourceTree = "<group>"; };
+		6B4C0F572C0314BA0070EF2E /* DFPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayer.h; sourceTree = "<group>"; };
+		6B4C0F582C0314BA0070EF2E /* DFPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayer.m; sourceTree = "<group>"; };
+		6B4C0F592C0314BA0070EF2E /* DFPlayerModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerModel.h; sourceTree = "<group>"; };
+		6B4C0F5A2C0314BA0070EF2E /* DFPlayerModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerModel.m; sourceTree = "<group>"; };
+		6B4C0F5B2C0314BA0070EF2E /* DFPlayerUIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFPlayerUIManager.h; sourceTree = "<group>"; };
+		6B4C0F5C2C0314BA0070EF2E /* DFPlayerUIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DFPlayerUIManager.m; sourceTree = "<group>"; };
 		6B4D23AF2B33DDBB005B718A /* imageVersionRenewTipView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = imageVersionRenewTipView.h; sourceTree = "<group>"; };
 		6B4D23B02B33DDBB005B718A /* imageVersionRenewTipView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = imageVersionRenewTipView.m; sourceTree = "<group>"; };
 		6B5B605E2B3BC8DE009A2AE2 /* fileTransferPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fileTransferPopView.h; sourceTree = "<group>"; };
@@ -2289,6 +2337,37 @@
 			path = resources;
 			sourceTree = "<group>";
 		};
+		6B4C0F562C0314BA0070EF2E /* supplement */ = {
+			isa = PBXGroup;
+			children = (
+				6B4C0F4C2C0314BA0070EF2E /* DFPlayerFileManager.h */,
+				6B4C0F4D2C0314BA0070EF2E /* DFPlayerFileManager.m */,
+				6B4C0F4E2C0314BA0070EF2E /* DFPlayerLyricsTableview.h */,
+				6B4C0F4F2C0314BA0070EF2E /* DFPlayerLyricsTableview.m */,
+				6B4C0F502C0314BA0070EF2E /* DFPlayerRequestManager.h */,
+				6B4C0F512C0314BA0070EF2E /* DFPlayerRequestManager.m */,
+				6B4C0F522C0314BA0070EF2E /* DFPlayerResourceLoader.h */,
+				6B4C0F532C0314BA0070EF2E /* DFPlayerResourceLoader.m */,
+				6B4C0F542C0314BA0070EF2E /* DFPlayerTool.h */,
+				6B4C0F552C0314BA0070EF2E /* DFPlayerTool.m */,
+			);
+			path = supplement;
+			sourceTree = "<group>";
+		};
+		6B4C0F5D2C0314BA0070EF2E /* DFPlayer */ = {
+			isa = PBXGroup;
+			children = (
+				6B4C0F562C0314BA0070EF2E /* supplement */,
+				6B4C0F572C0314BA0070EF2E /* DFPlayer.h */,
+				6B4C0F582C0314BA0070EF2E /* DFPlayer.m */,
+				6B4C0F592C0314BA0070EF2E /* DFPlayerModel.h */,
+				6B4C0F5A2C0314BA0070EF2E /* DFPlayerModel.m */,
+				6B4C0F5B2C0314BA0070EF2E /* DFPlayerUIManager.h */,
+				6B4C0F5C2C0314BA0070EF2E /* DFPlayerUIManager.m */,
+			);
+			path = DFPlayer;
+			sourceTree = "<group>";
+		};
 		6B5B60622B3D5F72009A2AE2 /* fileTransfeSet */ = {
 			isa = PBXGroup;
 			children = (
@@ -2580,6 +2659,7 @@
 		A003F6B727D841FF00715CBF /* Vendor */ = {
 			isa = PBXGroup;
 			children = (
+				6B4C0F5D2C0314BA0070EF2E /* DFPlayer */,
 				6BA08F462C01D05B00A2242D /* UploadManager */,
 				6BA08F1C2C01D01000A2242D /* DownLoadManager */,
 				6B304E9C2BEF6879004F5580 /* TencentOpenAPI.framework */,
@@ -2934,6 +3014,7 @@
 				183AE6D12A8CA98C00B11CB0 /* CloudPhoneAPI.h in Headers */,
 				6B07AC252BF85859005C2B0E /* ShareRecordModel.h in Headers */,
 				6BA08F372C01D01100A2242D /* SGDownloadSession.h in Headers */,
+				6B4C0F7E2C0314BA0070EF2E /* DFPlayerUIManager.h in Headers */,
 				6B5BE5932BFCA5FA00A1B9B3 /* videoPlayViewController.h in Headers */,
 				1868201D2AB97BE1005702A6 /* TipsQRCodeViewController.h in Headers */,
 				6B5B60602B3BC8DE009A2AE2 /* fileTransferPopView.h in Headers */,
@@ -2947,11 +3028,14 @@
 				1810F9012AA1839C00322116 /* PhoneTimeInfoModel.h in Headers */,
 				6BA533382B16E65500D1CB5C /* TvStatusModel.h in Headers */,
 				6BBB35E22AE935C000E4A59B /* DDYLanguageTool.h in Headers */,
+				6B4C0F6A2C0314BA0070EF2E /* DFPlayerRequestManager.h in Headers */,
 				6B1FBD262B4503E700926382 /* photosBackupsTaskModel.h in Headers */,
 				6B34DC4E2BF1BA11002DD1EF /* previewImageOrVideoViewController.h in Headers */,
 				6BFF26882AF8949F00FCB4F7 /* playerShowSecretkeyView.h in Headers */,
 				6BA08F4F2C01D05B00A2242D /* CWFileUploadManager.h in Headers */,
 				6BF0F3D52AD3937B000AA133 /* DeviceThirdIdModel.h in Headers */,
+				6B4C0F722C0314BA0070EF2E /* DFPlayerTool.h in Headers */,
+				6B4C0F622C0314BA0070EF2E /* DFPlayerFileManager.h in Headers */,
 				6B2170982B15CD9200656670 /* NSDictionary+Log.h in Headers */,
 				6B1FBD362B455DD600926382 /* PlayerViewController+backupsFile.h in Headers */,
 				18FCE5332AD12FE00020F623 /* ConnectTestViewController.h in Headers */,
@@ -2974,6 +3058,7 @@
 				181E84FB2A8F57A500292B96 /* ChangeLogoViewController.h in Headers */,
 				6B5B606A2B3D67B2009A2AE2 /* fileSetTableViewCell.h in Headers */,
 				18C4754F2A8E0DB5006129C0 /* MySetViewController.h in Headers */,
+				6B4C0F6E2C0314BA0070EF2E /* DFPlayerResourceLoader.h in Headers */,
 				18FCE53F2AD136670020F623 /* PlayerViewController+TouchPointXD.h in Headers */,
 				18FCE53E2AD136670020F623 /* PlayerViewController+AdjustBtnFrame.h in Headers */,
 				6B5BE5812BFC81E300A1B9B3 /* NASFileAndFolderModel.h in Headers */,
@@ -2991,6 +3076,7 @@
 				6B3F96342AD2A15A008E349E /* netWorkManager.h in Headers */,
 				6BA08F332C01D01100A2242D /* SGDownloadQueue.h in Headers */,
 				6B7EA7B02BF73DEB002D5CC2 /* addShareModel.h in Headers */,
+				6B4C0F7A2C0314BA0070EF2E /* DFPlayerModel.h in Headers */,
 				6B21708C2B14BDAA00656670 /* couldphoneSysInfoModel.h in Headers */,
 				6B72724F2B0B58E500C03F87 /* uploadFileRecordEditBottomView.h in Headers */,
 				6B6ABEE02BFF3DD000480BAC /* receiveHeadView.h in Headers */,
@@ -3003,6 +3089,7 @@
 				6B5D40332B4BE358000965CF /* downloadFileBottomView.h in Headers */,
 				6B1FBD222B43DAD200926382 /* backupsSetViewController.h in Headers */,
 				6B8FF6B92B04E19600800981 /* uploadFileRecordheadView.h in Headers */,
+				6B4C0F762C0314BA0070EF2E /* DFPlayer.h in Headers */,
 				18FCE5482AD15E750020F623 /* PlayerViewController+AppDelegate.h in Headers */,
 				6B72724B2B0AF59200C03F87 /* uploadFileRecordTableViewHeadView.h in Headers */,
 				6B72725F2B0E240F00C03F87 /* uploadFileRecordTableView.h in Headers */,
@@ -3022,6 +3109,7 @@
 				6BA08F532C01D05B00A2242D /* CWUploadTask.h in Headers */,
 				6B9714402BCD00CA00CE0096 /* ComontAlretType2ViewController.h in Headers */,
 				18EC79DC2ABC109F0084836A /* SetPWDSecondViewController.h in Headers */,
+				6B4C0F662C0314BA0070EF2E /* DFPlayerLyricsTableview.h in Headers */,
 				6B1F7FCA2C0064B500954720 /* boxReceiveFileRecordCell.h in Headers */,
 				6B0582852B0457C400D37290 /* uploadFileManager.h in Headers */,
 				6BA08F1F2C01D01100A2242D /* NSString+SGHashString.h in Headers */,
@@ -3114,6 +3202,7 @@
 				6BD506A92B9576A4006E7CB0 /* CloudPhoneAPI.h in Headers */,
 				6B07AC282BF85859005C2B0E /* ShareRecordModel.h in Headers */,
 				6BA08F382C01D01100A2242D /* SGDownloadSession.h in Headers */,
+				6B4C0F7F2C0314BA0070EF2E /* DFPlayerUIManager.h in Headers */,
 				6B5BE5952BFCA5FA00A1B9B3 /* videoPlayViewController.h in Headers */,
 				6BD506AA2B9576A4006E7CB0 /* TipsQRCodeViewController.h in Headers */,
 				6BD506AB2B9576A4006E7CB0 /* fileTransferPopView.h in Headers */,
@@ -3127,11 +3216,14 @@
 				6BD506B32B9576A4006E7CB0 /* PhoneTimeInfoModel.h in Headers */,
 				6BD506B42B9576A4006E7CB0 /* TvStatusModel.h in Headers */,
 				6BD506B52B9576A4006E7CB0 /* DDYLanguageTool.h in Headers */,
+				6B4C0F6B2C0314BA0070EF2E /* DFPlayerRequestManager.h in Headers */,
 				6BD506B62B9576A4006E7CB0 /* photosBackupsTaskModel.h in Headers */,
 				6B34DC502BF1BA11002DD1EF /* previewImageOrVideoViewController.h in Headers */,
 				6BD506B72B9576A4006E7CB0 /* playerShowSecretkeyView.h in Headers */,
 				6BA08F502C01D05B00A2242D /* CWFileUploadManager.h in Headers */,
 				6BD506B82B9576A4006E7CB0 /* DeviceThirdIdModel.h in Headers */,
+				6B4C0F732C0314BA0070EF2E /* DFPlayerTool.h in Headers */,
+				6B4C0F632C0314BA0070EF2E /* DFPlayerFileManager.h in Headers */,
 				6BD506B92B9576A4006E7CB0 /* NSDictionary+Log.h in Headers */,
 				6BD506BA2B9576A4006E7CB0 /* PlayerViewController+backupsFile.h in Headers */,
 				6BD506BB2B9576A4006E7CB0 /* ConnectTestViewController.h in Headers */,
@@ -3154,6 +3246,7 @@
 				6BD506C72B9576A4006E7CB0 /* ChangeLogoViewController.h in Headers */,
 				6BD506C82B9576A4006E7CB0 /* fileSetTableViewCell.h in Headers */,
 				6BD506C92B9576A4006E7CB0 /* MySetViewController.h in Headers */,
+				6B4C0F6F2C0314BA0070EF2E /* DFPlayerResourceLoader.h in Headers */,
 				6BD506CA2B9576A4006E7CB0 /* PlayerViewController+TouchPointXD.h in Headers */,
 				6BD506CB2B9576A4006E7CB0 /* PlayerViewController+AdjustBtnFrame.h in Headers */,
 				6B5BE5832BFC81E300A1B9B3 /* NASFileAndFolderModel.h in Headers */,
@@ -3171,6 +3264,7 @@
 				6BD506D32B9576A4006E7CB0 /* netWorkManager.h in Headers */,
 				6BA08F342C01D01100A2242D /* SGDownloadQueue.h in Headers */,
 				6B7EA7B22BF73DEB002D5CC2 /* addShareModel.h in Headers */,
+				6B4C0F7B2C0314BA0070EF2E /* DFPlayerModel.h in Headers */,
 				6BD506D42B9576A4006E7CB0 /* couldphoneSysInfoModel.h in Headers */,
 				6BD506D52B9576A4006E7CB0 /* uploadFileRecordEditBottomView.h in Headers */,
 				6B6ABEE22BFF3DD000480BAC /* receiveHeadView.h in Headers */,
@@ -3183,6 +3277,7 @@
 				6BD506DB2B9576A4006E7CB0 /* downloadFileBottomView.h in Headers */,
 				6BD506DC2B9576A4006E7CB0 /* backupsSetViewController.h in Headers */,
 				6BD506DD2B9576A4006E7CB0 /* uploadFileRecordheadView.h in Headers */,
+				6B4C0F772C0314BA0070EF2E /* DFPlayer.h in Headers */,
 				6BD506DE2B9576A4006E7CB0 /* PlayerViewController+AppDelegate.h in Headers */,
 				6BD506DF2B9576A4006E7CB0 /* uploadFileRecordTableViewHeadView.h in Headers */,
 				6BD506E02B9576A4006E7CB0 /* uploadFileRecordTableView.h in Headers */,
@@ -3202,6 +3297,7 @@
 				6BA08F542C01D05B00A2242D /* CWUploadTask.h in Headers */,
 				6B9714412BCD00CA00CE0096 /* ComontAlretType2ViewController.h in Headers */,
 				6BD506EB2B9576A4006E7CB0 /* SetPWDSecondViewController.h in Headers */,
+				6B4C0F672C0314BA0070EF2E /* DFPlayerLyricsTableview.h in Headers */,
 				6B1F7FCC2C0064B500954720 /* boxReceiveFileRecordCell.h in Headers */,
 				6BD506EC2B9576A4006E7CB0 /* uploadFileManager.h in Headers */,
 				6BA08F202C01D01100A2242D /* NSString+SGHashString.h in Headers */,
@@ -3651,6 +3747,7 @@
 				6BD507192B9576A4006E7CB0 /* ModifyPWDFirstViewController.m in Sources */,
 				6BA08F522C01D05B00A2242D /* CWFileUploadManager.m in Sources */,
 				6B1F7FCD2C0064B500954720 /* boxReceiveFileRecordCell.m in Sources */,
+				6B4C0F792C0314BA0070EF2E /* DFPlayer.m in Sources */,
 				6BD5071A2B9576A4006E7CB0 /* AFURLResponseSerialization.m in Sources */,
 				6BD5071B2B9576A4006E7CB0 /* HWHistoryViewController.m in Sources */,
 				6BD5071C2B9576A4006E7CB0 /* backupsSetViewController.m in Sources */,
@@ -3709,6 +3806,7 @@
 				6BD507432B9576A4006E7CB0 /* uploadFileRecordheadView.m in Sources */,
 				6BD507442B9576A4006E7CB0 /* HWAgreementViewController.m in Sources */,
 				6BD507452B9576A4006E7CB0 /* UIImageView+AFNetworking.m in Sources */,
+				6B4C0F652C0314BA0070EF2E /* DFPlayerFileManager.m in Sources */,
 				6B1F7FDF2C00ABAB00954720 /* downStatusModel.m in Sources */,
 				6B7EA7BF2BF759AC002D5CC2 /* shareSecretTableViewCell.m in Sources */,
 				6BD507462B9576A4006E7CB0 /* AFSecurityPolicy.m in Sources */,
@@ -3764,10 +3862,12 @@
 				6BD5076E2B9576A4006E7CB0 /* forgetPwdViewController.m in Sources */,
 				6BD5076F2B9576A4006E7CB0 /* uploadFileRecordTableViewHeadView.m in Sources */,
 				6BD507702B9576A4006E7CB0 /* JSONHTTPClient.m in Sources */,
+				6B4C0F752C0314BA0070EF2E /* DFPlayerTool.m in Sources */,
 				6BD507712B9576A4006E7CB0 /* AFImageDownloader.m in Sources */,
 				6BD507722B9576A4006E7CB0 /* UIColor+HZXColor.m in Sources */,
 				6BD507732B9576A4006E7CB0 /* CalculatorViewController.m in Sources */,
 				6B5BE5942BFCA5FA00A1B9B3 /* videoPlayViewController.m in Sources */,
+				6B4C0F6D2C0314BA0070EF2E /* DFPlayerRequestManager.m in Sources */,
 				6BD507742B9576A4006E7CB0 /* extraMediaEventModel.m in Sources */,
 				6BD507752B9576A4006E7CB0 /* couldPhoneFolderListModel.m in Sources */,
 				6BA08F362C01D01100A2242D /* SGDownloadQueue.m in Sources */,
@@ -3837,6 +3937,7 @@
 				6BD507A82B9576A4006E7CB0 /* uploadFileRecordBgScorllView.m in Sources */,
 				6BD507A92B9576A4006E7CB0 /* AboutViewController.m in Sources */,
 				6BD507AA2B9576A4006E7CB0 /* JSONModelArray.m in Sources */,
+				6B4C0F692C0314BA0070EF2E /* DFPlayerLyricsTableview.m in Sources */,
 				6BD507AB2B9576A4006E7CB0 /* AFURLSessionManager.m in Sources */,
 				6BD507AC2B9576A4006E7CB0 /* GuideLastView.m in Sources */,
 				6BD507AD2B9576A4006E7CB0 /* TvStatusModel.m in Sources */,
@@ -3858,6 +3959,7 @@
 				6BD507BC2B9576A4006E7CB0 /* netWorkManager.m in Sources */,
 				6BD507BD2B9576A4006E7CB0 /* HWBookmarkHeader.m in Sources */,
 				6BD507BE2B9576A4006E7CB0 /* HWDataManager.m in Sources */,
+				6B4C0F712C0314BA0070EF2E /* DFPlayerResourceLoader.m in Sources */,
 				6B3AD6862BF48DBA0096D6B7 /* shareRecordDetailsHWViewController.m in Sources */,
 				6BD507BF2B9576A4006E7CB0 /* MySetViewController.m in Sources */,
 				6BD507C02B9576A4006E7CB0 /* downloadFileBottomView.m in Sources */,
@@ -3878,6 +3980,7 @@
 				6BD507C92B9576A4006E7CB0 /* BaseModel.m in Sources */,
 				6B467BBA2BC7F7D70039A6A6 /* fileUploadToFileCenterModel.m in Sources */,
 				6BD507CA2B9576A4006E7CB0 /* HWHistoryModel.m in Sources */,
+				6B4C0F812C0314BA0070EF2E /* DFPlayerUIManager.m in Sources */,
 				6BD507CB2B9576A4006E7CB0 /* PlayerViewController+downloadThumbnailImage.m in Sources */,
 				6BD507CC2B9576A4006E7CB0 /* PlayerView.m in Sources */,
 				6BD507CD2B9576A4006E7CB0 /* HWToolBar.m in Sources */,
@@ -3886,6 +3989,7 @@
 				6BD507CF2B9576A4006E7CB0 /* JSONModel+networking.m in Sources */,
 				6BD507D02B9576A4006E7CB0 /* HWAboutViewController.m in Sources */,
 				6BD507D12B9576A4006E7CB0 /* SuperModel.m in Sources */,
+				6B4C0F7D2C0314BA0070EF2E /* DFPlayerModel.m in Sources */,
 				6BD507D22B9576A4006E7CB0 /* imageVersionRenewTipView.m in Sources */,
 				6B304E9B2BEF6058004F5580 /* customShareManageTool.m in Sources */,
 				6BD507D32B9576A4006E7CB0 /* uploadFileRecordEditBottomView.m in Sources */,
@@ -3915,6 +4019,7 @@
 				18F9CAFB2ABD35C4003FF71A /* ModifyPWDFirstViewController.m in Sources */,
 				6BA08F512C01D05B00A2242D /* CWFileUploadManager.m in Sources */,
 				6B1F7FCB2C0064B500954720 /* boxReceiveFileRecordCell.m in Sources */,
+				6B4C0F782C0314BA0070EF2E /* DFPlayer.m in Sources */,
 				183AE6542A8A2CF000B11CB0 /* AFURLResponseSerialization.m in Sources */,
 				A0295B1227ED938B009C5D8B /* HWHistoryViewController.m in Sources */,
 				6B1FBD232B43DAD200926382 /* backupsSetViewController.m in Sources */,
@@ -3973,6 +4078,7 @@
 				6B8FF6BA2B04E19600800981 /* uploadFileRecordheadView.m in Sources */,
 				A031DD7F27EC78C800909527 /* HWAgreementViewController.m in Sources */,
 				183AE64F2A8A2CF000B11CB0 /* UIImageView+AFNetworking.m in Sources */,
+				6B4C0F642C0314BA0070EF2E /* DFPlayerFileManager.m in Sources */,
 				6B1F7FDD2C00ABAB00954720 /* downStatusModel.m in Sources */,
 				6B7EA7BD2BF759AC002D5CC2 /* shareSecretTableViewCell.m in Sources */,
 				183AE6592A8A2CF000B11CB0 /* AFSecurityPolicy.m in Sources */,
@@ -4028,10 +4134,12 @@
 				6BFF268D2AF8E1C600FCB4F7 /* forgetPwdViewController.m in Sources */,
 				6B72724C2B0AF59200C03F87 /* uploadFileRecordTableViewHeadView.m in Sources */,
 				183AE6082A89CE3C00B11CB0 /* JSONHTTPClient.m in Sources */,
+				6B4C0F742C0314BA0070EF2E /* DFPlayerTool.m in Sources */,
 				183AE6532A8A2CF000B11CB0 /* AFImageDownloader.m in Sources */,
 				A003F6B327D841EE00715CBF /* UIColor+HZXColor.m in Sources */,
 				18E557222A3C5D75005CC84B /* CalculatorViewController.m in Sources */,
 				6B5BE5922BFCA5FA00A1B9B3 /* videoPlayViewController.m in Sources */,
+				6B4C0F6C2C0314BA0070EF2E /* DFPlayerRequestManager.m in Sources */,
 				6B1CC2C72B677F3E00AD4217 /* extraMediaEventModel.m in Sources */,
 				6B5D401B2B4A9850000965CF /* couldPhoneFolderListModel.m in Sources */,
 				6BA08F352C01D01100A2242D /* SGDownloadQueue.m in Sources */,
@@ -4101,6 +4209,7 @@
 				6B72725C2B0E22D000C03F87 /* uploadFileRecordBgScorllView.m in Sources */,
 				184C8AD62A949D5900F26650 /* AboutViewController.m in Sources */,
 				183AE6062A89CE3C00B11CB0 /* JSONModelArray.m in Sources */,
+				6B4C0F682C0314BA0070EF2E /* DFPlayerLyricsTableview.m in Sources */,
 				183AE6562A8A2CF000B11CB0 /* AFURLSessionManager.m in Sources */,
 				1868201A2AB94877005702A6 /* GuideLastView.m in Sources */,
 				6BA533392B16E65500D1CB5C /* TvStatusModel.m in Sources */,
@@ -4122,6 +4231,7 @@
 				6B3F96352AD2A15A008E349E /* netWorkManager.m in Sources */,
 				A031DD7127EC34E500909527 /* HWBookmarkHeader.m in Sources */,
 				A003F6D227D8425C00715CBF /* HWDataManager.m in Sources */,
+				6B4C0F702C0314BA0070EF2E /* DFPlayerResourceLoader.m in Sources */,
 				6B3AD6852BF48DBA0096D6B7 /* shareRecordDetailsHWViewController.m in Sources */,
 				18C475502A8E0DB5006129C0 /* MySetViewController.m in Sources */,
 				6B5D40342B4BE358000965CF /* downloadFileBottomView.m in Sources */,
@@ -4142,6 +4252,7 @@
 				A003F6A827D841C800715CBF /* BaseModel.m in Sources */,
 				6B467BB82BC7F7D70039A6A6 /* fileUploadToFileCenterModel.m in Sources */,
 				A0295B1627EDA0EC009C5D8B /* HWHistoryModel.m in Sources */,
+				6B4C0F802C0314BA0070EF2E /* DFPlayerUIManager.m in Sources */,
 				6B5D403C2B4BFEB9000965CF /* PlayerViewController+downloadThumbnailImage.m in Sources */,
 				183AE6B42A8CA00300B11CB0 /* PlayerView.m in Sources */,
 				A003F6F327D8593600715CBF /* HWToolBar.m in Sources */,
@@ -4150,6 +4261,7 @@
 				183AE60A2A89CE3C00B11CB0 /* JSONModel+networking.m in Sources */,
 				A0951D9427ED61F5000E6AC4 /* HWAboutViewController.m in Sources */,
 				183AE5E12A89CD3C00B11CB0 /* SuperModel.m in Sources */,
+				6B4C0F7C2C0314BA0070EF2E /* DFPlayerModel.m in Sources */,
 				6B4D23B22B33DDBC005B718A /* imageVersionRenewTipView.m in Sources */,
 				6B304E9A2BEF6058004F5580 /* customShareManageTool.m in Sources */,
 				6B7272502B0B58E500C03F87 /* uploadFileRecordEditBottomView.m in Sources */,

+ 338 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayer.h

@@ -0,0 +1,338 @@
+//
+//  DFPlayer.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/18.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+//
+//  DFPlayer当前版本:2.0.3
+//
+
+#import <Foundation/Foundation.h>
+#import <AVFoundation/AVFoundation.h>
+#import "DFPlayerModel.h"
+
+//播放器状态
+typedef NS_ENUM(NSInteger, DFPlayerState) {
+    DFPlayerStateFailed,     // 播放失败
+    DFPlayerStateBuffering,  // 缓冲中
+    DFPlayerStatePlaying,    // 播放中
+    DFPlayerStatePause,      // 暂停播放
+    DFPlayerStateStopped     // 停止播放
+};
+
+//播放模式
+typedef NS_ENUM(NSInteger, DFPlayerMode){
+    DFPlayerModeOnlyOnce,       //单曲只播放一次,默认
+    DFPlayerModeSingleCycle,    //单曲循环
+    DFPlayerModeOrderCycle,     //顺序循环
+    DFPlayerModeShuffleCycle    //随机循环
+};
+
+//状态码
+typedef NS_ENUM(NSUInteger, DFPlayerStatusCode) {
+    
+    DFPlayerStatusNoNetwork = 2100, //未缓存的网络音频,点击播放时若无网络会返回该状态码。缓冲完成前若断网也会返回该状态码。(PS:DFPlayer支持运行时断点续传,即缓冲时网络从无到有,可以断点续传,而某音频没缓冲完就退出app,再进入app没做断点续传,以上特点与QQ音乐一致)
+    DFPlayerStatusViaWWAN = 2101, //WWAN网络状态(注意:属性isObserveWWAN(默认NO)为YES时,对于未缓存的网络音频,点击该音频时开始缓冲时返回该状态码。而音频正在缓冲时,网络状态由wifi到wwan并不会返回该状态码,以上特点与QQ音乐一致)
+    
+    DFPlayerStatusTimeOut = 2200, //音频请求超时(根据服务器返回的状态码)
+    
+    DFPlayerStatusFailed = 2300, //音频无法播放(AVPlayerItemStatusFailed)
+    DFPlayerStatusUnknown = 2301, //未知错误(AVPlayerItemStatusUnknown)
+    
+    DFPlayerStatusCacheFail = 2400, //当前音频缓存失败
+    DFPlayerStatusCacheSucc = 2401  //当前音频缓存成功
+};
+
+
+@class DFPlayer;
+
+@protocol DFPlayerDataSource <NSObject>
+
+@required
+
+/**
+ 数据源1:音频数组
+ 
+ @param player DFPlayer
+ */
+- (NSArray<DFPlayerModel *> *)df_audioDataForPlayer:(DFPlayer *)player;
+
+@optional
+
+/**
+ 数据源2:音频信息
+ 调用df_playWithAudioId时,DFPlayer会调用此方法请求当前音频的信息
+ 根据player.currentAudioModel.audioId获取音频在数组中的位置,传入对应的音频信息model
+ 
+ @param player DFPlayer
+ */
+- (DFPlayerInfoModel *)df_audioInfoForPlayer:(DFPlayer *)player;
+
+@end
+
+
+@protocol DFPlayerDelegate <NSObject>
+
+@optional
+/**
+ 代理1:音频已经加入播放队列
+ 
+ @param player DFPlayer
+ */
+- (void)df_playerAudioAddToPlayQueue:(DFPlayer *)player;
+
+/**
+ 代理2:准备播放
+ 
+ @param player DFPlayer
+ */
+- (void)df_playerReadyToPlay:(DFPlayer *)player;
+
+/**
+ 代理3:缓冲进度代理  (属性isObserveBufferProgress(默认YES)为YES时有效)
+ 
+ @param player DFPlayer
+ @param bufferProgress 缓冲进度
+ */
+- (void)df_player:(DFPlayer *)player bufferProgress:(CGFloat)bufferProgress;
+
+/**
+ 代理4:播放进度代理 (属性isObserveProgress(默认YES)为YES时有效)
+ 
+ @param player DFPlayer
+ @param progress 播放进度
+ @param currentTime 当前播放到的时间
+ */
+- (void)df_player:(DFPlayer *)player progress:(CGFloat)progress currentTime:(CGFloat)currentTime;
+
+/**
+ 代理5:播放结束代理(默认播放结束后调用df_next。如果实现此代理,播放结束逻辑由您处理)
+ 
+ @param player FPlayer
+ */
+- (void)df_playerDidPlayToEndTime:(DFPlayer *)player;
+
+/**
+ 代理6:播放状态码代理(统一在主线程返回)
+ 
+ @param player DFPlayer
+ @param statusCode 状态码
+ */
+- (void)df_player:(DFPlayer *)player didGetStatusCode:(DFPlayerStatusCode)statusCode;
+
+/**
+ 代理7:播放器被系统打断代理(默认被系统打断暂停播放,打断结束检测能够播放则恢复播放。如果实现此代理,打断逻辑由您处理)
+ 
+ @param player DFPlayer
+ @param isInterrupted YES:被系统打断开始  NO:被系统打断结束
+ */
+- (void)df_player:(DFPlayer *)player isInterrupted:(BOOL)isInterrupted;
+
+/**
+ 代理8:监听耳机插入拔出代理(默认拨出耳机暂停播放,插入耳机不恢复播放。如果实现此代理,耳机插拔逻辑由您处理)
+ 
+ @param player DFPlayer
+ @param isHeadphone YES:插入 NO:拔出
+ */
+- (void)df_player:(DFPlayer *)player isHeadphone:(BOOL)isHeadphone;
+
+@end
+
+/**
+ DFPlayer播放管理器
+ */
+@interface DFPlayer : NSObject
+
+#pragma mark - 初始化和操作
+
+@property (nonatomic, weak) id<DFPlayerDataSource> dataSource;
+
+@property (nonatomic, weak) id<DFPlayerDelegate> delegate;
+
+/**
+ 播放器类型,默认AVAudioSessionCategoryPlayback
+ Tips:AVAudioSessionCategoryPlayback,需在工程里设置targets->capabilities->选择backgrounds modes->勾选audio,airplay,and picture in picture
+ */
+@property (nonatomic, assign) AVAudioSessionCategory category;
+
+/**
+ 播放模式,默认DFPlayerModeOnlyOnce。
+ */
+@property (nonatomic, assign) DFPlayerMode playMode;
+
+/**
+ 是否监听播放进度,默认YES
+ */
+@property (nonatomic, assign) BOOL isObserveProgress;
+
+/**
+ 是否监听缓冲进度,默认YES
+ */
+@property (nonatomic, assign) BOOL isObserveBufferProgress;
+
+/**
+ 是否需要缓存,默认YES
+ */
+@property (nonatomic, assign) BOOL isNeedCache;
+
+/**
+ 是否监测WWAN无线广域网(2g/3g/4g),默认NO。
+ 播放本地音频(工程目录和沙盒文件)不监测。
+ 播放网络音频时,DFPlayer为您实现无网络有缓存播放缓存,无网络无缓存返回无网络错误码,wifi下自动播放。开启该属性,当网络为WWAN时,通过代理6返回状态码DFPlayerStatusViaWWAN。
+ */
+@property (nonatomic, assign) BOOL isObserveWWAN;
+
+/**
+ 是否监听服务器文件修改时间,默认NO。
+ 第一次请求某资源时,DFPlayer缓存文件的同时会记录文件在服务器端的修改时间。
+ 开启该属性,以后播放该资源时,DFPlayer会判断服务端文件是否修改过,修改过则加载新资源,没有修改过则播放缓存文件。
+ 关闭此属性,有缓存时将直接播放缓存,不做更新校验,在弱网环境下播放响应速度更快。
+ 无网络连接时,有缓存直接播放缓存文件。
+ */
+@property (nonatomic, assign) BOOL isObserveFileModifiedTime;
+
+/**
+ 单例
+ */
++ (DFPlayer *)sharedPlayer;
+
+/**
+ 初始化播放器
+ 
+ @param userId 用户Id。
+ isNeedCache(默认YES)为YES时,若同一设备登录不同账号:
+ 1.userId不为空时,DFPlayer将为每位用户建立不同的缓存文件目录。例如,user_001,user_002...
+ 2.userId为nil或@""时,统一使用DFPlayerCache文件夹下的user_public作为缓存目录。
+ isNeedCache为NO时,userId设置无效,此时不会在沙盒创建缓存目录。
+ */
+- (void)df_initPlayerWithUserId:(NSString *)userId;
+
+/**
+ 刷新数据源数据
+ */
+- (void)df_reloadData;
+
+/**
+ 选择audioId对应的音频开始播放。
+ 说明:DFPlayer通过数据源方法提前获取数据,通过df_playWithAudioId选择对应音频播放。
+ 而在删除、增加音频后需要调用[[DFPlayer shareInstance] df_reloadData];刷新数据。
+ */
+- (void)df_playWithAudioId:(NSUInteger)audioId;
+
+/**
+ 播放
+ */
+- (void)df_play;
+
+/**
+ 暂停
+ */
+- (void)df_pause;
+
+/**
+ 下一首
+ */
+- (void)df_next;
+
+/**
+ 上一首
+ */
+- (void)df_last;
+
+/**
+ 音频跳转
+ 
+ @param value 时间百分比(要跳转到的时间/总时间)
+ @param completionBlock seek结束
+ */
+- (void)df_seekToTime:(CGFloat)value completionBlock:(void(^)(void))completionBlock;
+
+/**
+ 倍速播放(iOS10之后系统支持的倍速常数有0.50, 0.67, 0.80, 1.0, 1.25, 1.50和2.0)
+ @param rate 倍速
+ */
+- (void)df_setRate:(CGFloat)rate;
+
+/**
+ 释放播放器,还原其他播放器
+ */
+- (void)df_deallocPlayer;
+
+
+#pragma mark - 状态类
+
+/**
+ 播放器状态
+ */
+@property (nonatomic, readonly, assign) DFPlayerState state;
+
+/**
+ 当前正在播放的音频model
+ */
+@property (nonatomic, readonly, strong) DFPlayerModel *currentAudioModel;
+
+/**
+ 当前正在播放的音频信息model
+ */
+@property (nonatomic, readonly, strong) DFPlayerInfoModel *currentAudioInfoModel;
+
+/**
+ 当前音频缓冲进度
+ */
+@property (nonatomic, readonly, assign) CGFloat bufferProgress;
+
+/**
+ 当前音频播放进度
+ */
+@property (nonatomic, readonly, assign) CGFloat progress;
+
+/**
+ 当前音频当前时间
+ */
+@property (nonatomic, readonly, assign) CGFloat currentTime;
+
+/**
+ 当前音频总时长
+ */
+@property (nonatomic, readonly, assign) CGFloat totalTime;
+
+#pragma mark - 缓存相关
+/**
+ audioUrl对应的音频在本地的缓存地址
+ 
+ @param audioUrl 网络音频url
+ @return 无缓存时返回nil
+ */
+- (NSString *)df_cachePath:(NSURL *)audioUrl;
+
+/**
+ DFPlayer的缓存大小
+ 
+ @param currentUser YES:当前用户  NO:所有用户
+ @return 缓存大小
+ */
+- (CGFloat)df_cacheSize:(BOOL)currentUser;
+
+/**
+ 清除音频缓存
+ 
+ @param audioUrl 网络音频url
+ @return 是否清除成功(无缓存时返回YES)
+ */
+- (BOOL)df_clearAudioCache:(NSURL *)audioUrl;
+
+/**
+ 清除用户缓存
+ 
+ @param currentUser YES:清除当前用户缓存  NO:清除所有用户缓存
+ @return 是否清除成功(无缓存时返回YES)
+ */
+- (BOOL)df_clearUserCache:(BOOL)currentUser;
+
+@end
+
+
+
+

+ 862 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayer.m

@@ -0,0 +1,862 @@
+//
+//  DFPlayer.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/18.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayer.h"
+#import "DFPlayerFileManager.h"
+#import "DFPlayerResourceLoader.h"
+#import "DFPlayerTool.h"
+#import <MediaPlayer/MediaPlayer.h>
+
+/**Asset KEY*/
+NSString * const DFPlayableKey                  = @"playable";
+/**PlayerItem KEY*/
+NSString * const DFStatusKey                    = @"status";
+NSString * const DFLoadedTimeRangesKey          = @"loadedTimeRanges";
+NSString * const DFPlaybackBufferEmptyKey       = @"playbackBufferEmpty";
+NSString * const DFPlaybackLikelyToKeepUpKey    = @"playbackLikelyToKeepUp";
+
+@interface DFPlayer()<DFPlayerResourceLoaderDelegate>
+{
+    BOOL _isOtherPlaying; // 其他应用是否正在播放
+    BOOL _isBackground; // 是否进入后台
+    BOOL _isCached; // 当前音频是否缓存
+    BOOL _isSeek; // 正在seek
+    BOOL _isSeekWaiting; // seek 等待
+    BOOL _isNaturalToEndTime; // 是否是自然结束
+    dispatch_group_t _netGroupQueue; // 组队列-网络
+    dispatch_group_t _dataGroupQueue; // 组队列-数据
+    NSInteger _currentAudioId; // 当前正在播放的音频Id
+    NSInteger _randomIndex; // 随机数组元素index
+    NSInteger _playIndex1; // 播放顺序标识
+    NSInteger _playIndex2; // 播放顺序标识
+    CGFloat _seekValue; // seek value
+    NSMutableDictionary *_remoteInfoDictionary; // 控制中心信息
+}
+/** player */
+@property (nonatomic, strong) AVPlayer          *player;
+/** playerItem */
+@property (nonatomic, strong) AVPlayerItem      *playerItem;
+/** 播放进度监测 */
+@property (nonatomic, strong) id                timeObserver;
+/** 随机数组 */
+@property (nonatomic, strong) NSMutableArray    *randomIndexArray;
+/** 资源下载器 */
+@property (nonatomic, strong) DFPlayerResourceLoader *resourceLoader;
+/** model数据数组 */
+@property (nonatomic, strong) NSMutableArray<DFPlayerModel *> *playerModelArray;
+
+@property (nonatomic, copy) void(^seekCompletionBlock)(void);
+
+@property (nonatomic, readwrite, strong) DFPlayerModel *currentAudioModel;
+@property (nonatomic, readwrite, strong) DFPlayerInfoModel *currentAudioInfoModel;
+@property (nonatomic, readwrite, assign) DFPlayerState state;
+@property (nonatomic, readwrite, assign) CGFloat bufferProgress;
+@property (nonatomic, readwrite, assign) CGFloat progress;
+@property (nonatomic, readwrite, assign) CGFloat currentTime;
+@property (nonatomic, readwrite, assign) CGFloat totalTime;
+
+@end
+
+@implementation DFPlayer
+
+#pragma mark - 初始化
++ (DFPlayer *)sharedPlayer {
+    static DFPlayer *player = nil;
+    static dispatch_once_t predicate;
+    dispatch_once(&predicate, ^{
+        player = [[[self class] alloc] init];
+    });
+    return player;
+}
+
+- (void)dealloc{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+#pragma mark - 初始化播放器
+- (void)df_initPlayerWithUserId:(NSString *)userId{
+    [DFPlayerFileManager df_saveUserId:userId];
+    
+    [[AVAudioSession sharedInstance] setActive:YES error:nil];
+    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
+    
+    _isOtherPlaying = [AVAudioSession sharedInstance].otherAudioPlaying;
+    
+    self.playMode = DFPlayerModeOnlyOnce;
+    self.state = DFPlayerStateStopped;
+    self.isObserveProgress          = YES;
+    self.isObserveBufferProgress    = YES;
+    self.isNeedCache                = YES;
+    self.isObserveFileModifiedTime  = NO;
+    self.isObserveWWAN              = NO;
+    _isCached       = NO;
+    _isBackground   = NO;
+    _randomIndex    = -1;
+    _playIndex2     = 0;
+    
+    _netGroupQueue  = dispatch_group_create();
+    _dataGroupQueue = dispatch_group_create();
+    
+    [self addNetObserver];
+    [self addPlayerObserver];
+    [self addRemoteControlHandler];
+}
+
+- (void)addNetObserver{
+    static dispatch_once_t token1;
+    dispatch_once(&token1, ^{
+        dispatch_group_enter(self->_netGroupQueue);
+    });
+    dispatch_group_async(_netGroupQueue, DFPlayerDefaultGlobalQueue, ^{
+        [DFPlayerTool startMonitoringNetworkStatus:^(DFPlayerNetworkStatus networkStatus) {
+            static dispatch_once_t token2;
+            dispatch_once(&token2, ^{
+                dispatch_group_leave(self->_netGroupQueue);
+            });
+        }];
+    });
+}
+
+- (void)addPlayerObserver{
+    //将要进入后台
+    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+    [notificationCenter addObserver:self
+                           selector:@selector(df_playerWillResignActive)
+                               name:UIApplicationWillResignActiveNotification
+                             object:nil];
+    //已经进入前台
+    [notificationCenter addObserver:self
+                           selector:@selector(df_playerDidEnterForeground)
+                               name:UIApplicationDidBecomeActiveNotification
+                             object:nil];
+    //监测耳机
+    [notificationCenter addObserver:self
+                           selector:@selector(df_playerAudioRouteChange:)
+                               name:AVAudioSessionRouteChangeNotification
+                             object:nil];
+    //监听播放器被打断(别的软件播放音乐,来电话)
+    [notificationCenter addObserver:self
+                           selector:@selector(df_playerAudioBeInterrupted:)
+                               name:AVAudioSessionInterruptionNotification
+                             object:[AVAudioSession sharedInstance]];
+    //监测其他app是否占据AudioSession
+    [notificationCenter addObserver:self
+                           selector:@selector(df_playerSecondaryAudioHint:)
+                               name:AVAudioSessionSilenceSecondaryAudioHintNotification
+                             object:nil];
+}
+
+- (void)df_playerWillResignActive{
+    _isBackground = YES;
+}
+
+- (void)df_playerDidEnterForeground{
+    _isBackground = NO;
+}
+
+- (void)df_playerAudioRouteChange:(NSNotification *)notification{
+    NSInteger routeChangeReason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] integerValue];
+    switch (routeChangeReason) {
+        case AVAudioSessionRouteChangeReasonNewDeviceAvailable://耳机插入
+            if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:isHeadphone:)]) {
+                [self.delegate df_player:self isHeadphone:YES];
+            }
+            break;
+        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable://耳机拔出,停止播放操作
+            if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:isHeadphone:)]) {
+                [self.delegate df_player:self isHeadphone:NO];
+            }else{
+                [self df_pause];
+            }
+            break;
+        case AVAudioSessionRouteChangeReasonCategoryChange:
+            //
+            break;
+        default:
+            break;
+    }
+}
+
+- (void)df_playerAudioBeInterrupted:(NSNotification *)notification{
+    NSDictionary *dic = notification.userInfo;
+    if ([dic[AVAudioSessionInterruptionTypeKey] integerValue] == 1) {//打断开始
+        if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:isInterrupted:)]) {
+            [self.delegate df_player:self isInterrupted:YES];
+        }else{
+            [self df_pause];
+        }
+    }else {//打断结束
+        if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:isInterrupted:)]) {
+            [self.delegate df_player:self isInterrupted:NO];
+        }else{
+            if ([notification.userInfo[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue] == 1) {
+                [self df_play];
+            }
+        }
+    }
+}
+
+- (void)df_playerSecondaryAudioHint:(NSNotification *)notification{
+    //    NSInteger type = [notification.userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] integerValue];
+}
+
+-(void)df_playerDidPlayToEndTime:(NSNotification *)notification{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(df_playerDidPlayToEndTime:)]) {
+        [self.delegate df_playerDidPlayToEndTime:self];
+    }else{
+        _isNaturalToEndTime = YES;
+        [self df_next];
+    }
+}
+
+/**远程线控*/
+- (void)addRemoteControlHandler{
+    if (@available (iOS 7.1, *)) {
+        [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
+        MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
+        [self addRemoteCommand:center.playCommand selector:@selector(df_play)];
+        [self addRemoteCommand:center.pauseCommand selector:@selector(df_pause)];
+        [self addRemoteCommand:center.previousTrackCommand selector:@selector(df_last)];
+        [self addRemoteCommand:center.nextTrackCommand selector:@selector(df_next)];
+        [center.togglePlayPauseCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
+            if ([DFPlayer sharedPlayer].state == DFPlayerStatePlaying) {
+                [[DFPlayer sharedPlayer] df_pause];
+            }else{
+                [[DFPlayer sharedPlayer] df_play];
+            }
+            return MPRemoteCommandHandlerStatusSuccess;
+        }];
+        
+        if (@available (iOS 9.1,*)) {
+            [center.changePlaybackPositionCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
+                MPChangePlaybackPositionCommandEvent *positionEvent = (MPChangePlaybackPositionCommandEvent *)event;
+                if (self.totalTime > 0) {
+                    [self df_seekToTime:positionEvent.positionTime / self.totalTime completionBlock:nil];
+                }
+                return MPRemoteCommandHandlerStatusSuccess;
+            }];
+        }
+    }
+}
+
+- (void)addRemoteCommand:(MPRemoteCommand *)command selector:(SEL)selector{
+    [command addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
+        if ([self respondsToSelector:selector]) {
+            IMP imp = [self methodForSelector:selector];
+            void (*func)(id, SEL) = (void *)imp;
+            func(self, selector);
+        }
+        return MPRemoteCommandHandlerStatusSuccess;
+    }];
+}
+
+#pragma mark - 数据源
+
+- (void)df_reloadData{
+    if (self.dataSource && [self.dataSource respondsToSelector:@selector(df_audioDataForPlayer:)]) {
+        if (!self.playerModelArray) {
+            self.playerModelArray = [NSMutableArray array];
+        }
+        if (self.playerModelArray.count != 0) {
+            [self.playerModelArray removeAllObjects];
+        }
+        dispatch_group_enter(_dataGroupQueue);
+        dispatch_group_async(_dataGroupQueue, DFPlayerHighGlobalQueue, ^{
+            dispatch_async(DFPlayerHighGlobalQueue, ^{
+                
+                [self.playerModelArray addObjectsFromArray:[self.dataSource df_audioDataForPlayer:self]];
+                
+                //更新随机数组
+                [self updateRandomIndexArray];
+                
+                //更新currentAudioId
+                if (self.currentAudioModel.audioUrl) {
+                    [self.playerModelArray enumerateObjectsWithOptions:(NSEnumerationConcurrent) usingBlock:^(DFPlayerModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+                        if ([obj.audioUrl.absoluteString isEqualToString:self.currentAudioModel.audioUrl.absoluteString]) {
+                            self.currentAudioModel.audioId = idx;
+                            self->_currentAudioId = idx;
+                            *stop = YES;
+                        }
+                    }];
+                }
+                dispatch_group_leave(self->_dataGroupQueue);
+            });
+        });
+    }
+}
+
+#pragma mark - 播放 IMPORTANT
+
+- (void)df_playWithAudioId:(NSUInteger)audioId{
+    dispatch_group_notify(_dataGroupQueue, DFPlayerHighGlobalQueue, ^{
+        if (self.playerModelArray.count > audioId) {
+            self.currentAudioModel = self.playerModelArray[audioId];
+            self->_currentAudioId = audioId;
+            [self audioPrePlay];
+        }
+    });
+}
+
+- (void)audioPrePlay{
+    [self reset];
+
+    if (![DFPlayerTool isNSURL:self.currentAudioModel.audioUrl]) {
+        return;
+    }
+
+    if (self.dataSource && [self.dataSource respondsToSelector:@selector(df_audioInfoForPlayer:)]) {
+        self.currentAudioInfoModel = [self.dataSource df_audioInfoForPlayer:self];
+    }
+
+    if (self.delegate && [self.delegate respondsToSelector:@selector(df_playerAudioAddToPlayQueue:)]) {
+        [self.delegate df_playerAudioAddToPlayQueue:self];
+    }
+
+    if ([DFPlayerTool isLocalAudio:self.currentAudioModel.audioUrl]) {
+//        NSLog(@"-- DFPlayer:本地音频,Id:%ld",(unsigned long)self.currentAudioModel.audioId);
+        _isCached = YES;
+        [self loadPlayerItemWithURL:self.currentAudioModel.audioUrl];
+    }else{
+        NSString *cachePath = [DFPlayerFileManager df_cachePath:self.currentAudioModel.audioUrl];
+        _isCached = cachePath ? YES : NO;
+//        NSLog(@"-- DFPlayer:网络音频,Id:%ld 缓存:%@",(unsigned long)self.currentAudioModel.audioId, cachePath ? @"有" : @"无");
+        dispatch_group_notify(_netGroupQueue, DFPlayerDefaultGlobalQueue, ^{
+            if ([DFPlayerTool networkStatus] == DFPlayerNetworkStatusUnknown ||
+                [DFPlayerTool networkStatus] == DFPlayerNetworkStatusNotReachable){
+                if (cachePath){//有缓存,播放缓存
+                    [self loadPlayerItemWithURL:[NSURL fileURLWithPath:cachePath]];
+                }else{//无缓存,提示联网
+                    [self df_getStatusCode:DFPlayerStatusNoNetwork];
+                }
+            }else{
+                if (!self.isNeedCache){//不需要缓存
+                    // WWAN网络警告
+                    if (self.isObserveWWAN && [DFPlayerTool networkStatus] == DFPlayerNetworkStatusReachableViaWWAN) {
+                        [self df_getStatusCode:DFPlayerStatusViaWWAN];
+                        return;
+                    }
+                    [self loadPlayerItemWithURL:self.currentAudioModel.audioUrl];
+                }else{//需要缓存
+                    if (cachePath && !self.isObserveFileModifiedTime) {
+                        //有缓存且不监听改变时间,直接播放缓存
+                        [self loadPlayerItemWithURL:[NSURL fileURLWithPath:cachePath]];
+                    }else{//无缓存 或 需要兼听
+                        // WWAN网络警告
+                        if (self.isObserveWWAN && [DFPlayerTool networkStatus] == DFPlayerNetworkStatusReachableViaWWAN) {
+                            [self df_getStatusCode:DFPlayerStatusViaWWAN];
+                            return;
+                        }
+                        [self loadAudioWithCachePath:cachePath];
+                    }
+                }
+            }
+        });
+    }
+}
+
+- (void)loadAudioWithCachePath:(NSString *)cachePath{
+    self.resourceLoader = [[DFPlayerResourceLoader alloc] init];
+    self.resourceLoader.delegate = self;
+    self.resourceLoader.isCached = _isCached;
+    self.resourceLoader.isObserveFileModifiedTime = self.isObserveFileModifiedTime;
+    
+    NSURL *customUrl = [DFPlayerTool customURL:self.currentAudioModel.audioUrl];
+    if (!customUrl) {
+        return;
+    }
+    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:customUrl options:nil];
+    [asset.resourceLoader setDelegate:self.resourceLoader queue:dispatch_get_main_queue()];
+    [asset loadValuesAsynchronouslyForKeys:@[DFPlayableKey] completionHandler:^{
+        dispatch_async( dispatch_get_main_queue(),^{
+            if (!asset.playable) {
+                self.state = DFPlayerStateFailed;
+                [self.resourceLoader stopDownload];
+                [asset cancelLoading];
+            }
+        });
+    }];
+    DFPlayerWeakSelf
+    self.resourceLoader.checkStatusBlock = ^(NSInteger statusCode){
+        DFPlayerStrongSelf
+        if (statusCode == 200) {
+            [sSelf loadPlayerItemWithAsset:asset];
+        }else if (statusCode == 304) { // 服务器文件未变化
+            [sSelf loadPlayerItemWithURL:[NSURL fileURLWithPath:cachePath]];
+        }else if (statusCode == 206){
+            
+        }
+    };
+}
+
+- (void)loadPlayerItemWithURL:(NSURL *)URL{
+    self.playerItem = [[AVPlayerItem alloc] initWithURL:URL];
+    [self loadPlayer];
+}
+
+- (void)loadPlayerItemWithAsset:(AVURLAsset *)asset{
+    self.playerItem = [AVPlayerItem playerItemWithAsset:asset];
+    [self loadPlayer];
+}
+
+- (void)loadPlayer{
+    self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];
+    if (@available(iOS 10.0,*)) {
+        self.player.automaticallyWaitsToMinimizeStalling = NO;
+    }
+    [self df_play];
+    [self addProgressObserver];
+    [self addPlayingCenterInfo];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
+    if (object == self.player.currentItem) {
+        if ([keyPath isEqualToString:DFStatusKey]) {
+            AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
+            switch (status) {
+                case AVPlayerItemStatusUnknown:
+                    self.state = DFPlayerStateFailed;
+                    [self df_getStatusCode:DFPlayerStatusUnknown];
+                    break;
+                case AVPlayerItemStatusReadyToPlay:
+                    if (self.delegate && [self.delegate respondsToSelector:@selector(df_playerReadyToPlay:)]) {
+                        [self.delegate df_playerReadyToPlay:self];
+                    }
+                    break;
+                case AVPlayerItemStatusFailed:
+                    //NSError *error = nil;//self.player.currentItem.error;
+                    NSLog(@"%@",self.player.currentItem.error);
+                    
+                    self.state = DFPlayerStateFailed;
+                    [self df_getStatusCode:DFPlayerStatusFailed];
+                    break;
+                default:
+                    break;
+            }
+        }else if ([keyPath isEqualToString:DFLoadedTimeRangesKey]) {
+            [self addBufferProgressObserver];
+        }else if ([keyPath isEqualToString:DFPlaybackBufferEmptyKey]) {
+            if (self.playerItem.playbackBufferEmpty) {
+                self.state = DFPlayerStateBuffering;
+            }
+        }else if ([keyPath isEqualToString:DFPlaybackLikelyToKeepUpKey]) {
+            
+        }
+    }else{
+        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+    }
+}
+
+#pragma mark - DFPlayerResourceLoaderDelegate
+/**下载出错*/
+- (void)loader:(DFPlayerResourceLoader *)loader requestError:(NSInteger)errorCode{
+    if (errorCode == NSURLErrorTimedOut) {
+        [self df_getStatusCode:DFPlayerStatusTimeOut];
+    }else if ([DFPlayerTool networkStatus] == DFPlayerNetworkStatusNotReachable ||
+              [DFPlayerTool networkStatus] == DFPlayerNetworkStatusUnknown) {
+        [self df_getStatusCode:DFPlayerStatusNoNetwork];
+    }
+}
+
+/**是否完成缓存*/
+- (void)loader:(DFPlayerResourceLoader *)loader isCached:(BOOL)isCached{
+    _isCached = isCached;
+    NSUInteger status = isCached ? DFPlayerStatusCacheSucc : DFPlayerStatusCacheFail;
+    [self df_getStatusCode:status];
+}
+
+
+#pragma mark - 缓冲进度 播放进度 歌曲锁屏信息 音频跳转
+
+- (void)addBufferProgressObserver{
+    self.totalTime = CMTimeGetSeconds(self.playerItem.duration);
+    if (!self.isObserveBufferProgress) {
+        return;
+    }
+    CMTimeRange timeRange   = [self.playerItem.loadedTimeRanges.firstObject CMTimeRangeValue];
+    CGFloat startSeconds    = CMTimeGetSeconds(timeRange.start);
+    CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
+    if (self.totalTime != 0) {//避免出现inf
+        self.bufferProgress = (startSeconds + durationSeconds) / self.totalTime;
+    }
+    if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:bufferProgress:)]) {
+        [self.delegate df_player:self bufferProgress:self.bufferProgress];
+    }
+
+    if (_isSeekWaiting) {
+        if (self.bufferProgress > _seekValue) {
+            _isSeekWaiting = NO;
+            [self didSeekToTime:_seekValue completionBlock:^{
+                if (self.seekCompletionBlock) {
+                    self.seekCompletionBlock();
+                }
+            }];
+        }
+    }
+}
+
+- (void)addProgressObserver{
+    if (!self.isObserveProgress) {
+        return;
+    }
+
+    DFPlayerWeakSelf
+    self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0, 1.0) queue:nil usingBlock:^(CMTime time){
+        DFPlayerStrongSelf
+        if (sSelf->_isSeek) {
+            return;
+        }
+        AVPlayerItem *currentItem = sSelf.playerItem;
+        NSArray *loadedRanges = currentItem.seekableTimeRanges;
+        if (loadedRanges.count > 0 && currentItem.duration.timescale != 0){
+            CGFloat currentT = (CGFloat)CMTimeGetSeconds(time);
+            sSelf.currentTime = currentT;
+            if (sSelf.totalTime != 0) {//避免出现inf
+                sSelf.progress = CMTimeGetSeconds([currentItem currentTime]) / sSelf.totalTime;
+            }
+            if (sSelf.delegate && [sSelf.delegate respondsToSelector:@selector(df_player:progress:currentTime:)]) {
+                [sSelf.delegate df_player:sSelf progress:sSelf.progress currentTime:currentT];
+            }
+
+            [sSelf updatePlayingCenterInfo];
+        }
+    }];
+}
+
+- (void)addPlayingCenterInfo{
+    _remoteInfoDictionary = [NSMutableDictionary dictionary];
+    
+    if (self.currentAudioInfoModel.audioName) {
+        _remoteInfoDictionary[MPMediaItemPropertyTitle] = self.currentAudioInfoModel.audioName;
+    }
+    if (self.currentAudioInfoModel.audioAlbum) {
+        _remoteInfoDictionary[MPMediaItemPropertyAlbumTitle] = self.currentAudioInfoModel.audioAlbum;
+    }
+    if (self.currentAudioInfoModel.audioSinger) {
+        _remoteInfoDictionary[MPMediaItemPropertyArtist] = self.currentAudioInfoModel.audioSinger;
+    }
+    if ([self.currentAudioInfoModel.audioImage isKindOfClass:[UIImage class]] && self.currentAudioInfoModel.audioImage) {
+        if (@available(iOS 10.0, *)) {
+            DFPlayerWeakSelf
+            MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithBoundsSize:self.currentAudioInfoModel.audioImage.size
+                                                                          requestHandler:^UIImage * _Nonnull(CGSize size) {
+                return wSelf.currentAudioInfoModel.audioImage;
+            }];
+            _remoteInfoDictionary[MPMediaItemPropertyArtwork] = artwork;
+        } else {
+            MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:self.currentAudioInfoModel.audioImage];
+            _remoteInfoDictionary[MPMediaItemPropertyArtwork] = artwork;
+        }
+    }
+    _remoteInfoDictionary[MPNowPlayingInfoPropertyPlaybackRate] = [NSNumber numberWithFloat:1.0];
+    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = _remoteInfoDictionary;
+}
+
+- (void)updatePlayingCenterInfo{
+    if (!_isBackground) {return;}
+    _remoteInfoDictionary[MPNowPlayingInfoPropertyElapsedPlaybackTime] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.currentTime)];
+    _remoteInfoDictionary[MPMediaItemPropertyPlaybackDuration] = [NSNumber numberWithDouble:CMTimeGetSeconds(self.playerItem.duration)];
+    [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = _remoteInfoDictionary;
+}
+
+- (void)df_seekToTime:(CGFloat)value completionBlock:(void (^)(void))completionBlock{
+    _isSeek = YES;
+    // 先暂停
+    if (self.state == DFPlayerStatePlaying) {
+        [self df_pause];
+    }
+    if (self.bufferProgress < value) {
+        _isSeekWaiting = YES;
+        _seekValue = value;
+        if (completionBlock) {
+            self.seekCompletionBlock = completionBlock;
+        }
+    }else{
+        _isSeekWaiting = NO;
+        [self didSeekToTime:value completionBlock:completionBlock];
+    }
+}
+
+- (void)didSeekToTime:(CGFloat)value completionBlock:(void (^)(void))completionBlock{
+    [self.player seekToTime:CMTimeMake(floorf(self.totalTime * value), 1)
+            toleranceBefore:kCMTimeZero
+             toleranceAfter:kCMTimeZero
+          completionHandler:^(BOOL finished) {
+        if (finished) {
+            [self df_play];
+            self->_isSeek = NO;
+            if (completionBlock) {
+                completionBlock();
+            }
+        }
+    }];
+}
+
+/**倍速播放*/
+- (void)df_setRate:(CGFloat)rate{
+    for (AVPlayerItemTrack *track in self.playerItem.tracks){
+        if ([track.assetTrack.mediaType isEqual:AVMediaTypeAudio]){
+            track.enabled = YES;
+        }
+    }
+    self.player.rate = rate;
+}
+
+/**释放播放器*/
+- (void)df_deallocPlayer{
+    
+    [self reset];
+    
+    self.state = DFPlayerStateStopped;
+    
+    [DFPlayerTool stopMonitoringNetwork];
+    
+    if (@available(iOS 7.1, *)) {
+        [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
+        MPRemoteCommandCenter *center = [MPRemoteCommandCenter sharedCommandCenter];
+        [[center playCommand] removeTarget:self];
+        [[center pauseCommand] removeTarget:self];
+        [[center nextTrackCommand] removeTarget:self];
+        [[center previousTrackCommand] removeTarget:self];
+        [[center togglePlayPauseCommand] removeTarget:self];
+        if(@available(iOS 9.1, *)) {
+            [center.changePlaybackPositionCommand removeTarget:self];
+        }
+    }
+    
+    if (_isOtherPlaying) {
+        [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
+    }else{
+        [[AVAudioSession sharedInstance] setActive:NO error:nil];
+    }
+    [self.player.currentItem cancelPendingSeeks];
+    [self.player.currentItem.asset cancelLoading];
+    
+    if (self.randomIndexArray) {
+        self.randomIndexArray = nil;
+    }
+    
+    if (self.playerModelArray) {
+        self.playerModelArray = nil;
+    }
+    
+    if (self.playerItem) {
+        self.playerItem = nil;
+    }
+    
+    if (self.player) {
+        self.player = nil;
+    }
+}
+
+- (void)reset{
+    if (self.state == DFPlayerStatePlaying) {
+        [self df_pause];
+    }
+    
+    //停止下载
+    if (self.resourceLoader) {
+        [self.resourceLoader stopDownload];
+    }
+    
+    //移除进度观察者
+    if (self.timeObserver) {
+        [self.player removeTimeObserver:self.timeObserver];
+        self.timeObserver = nil;
+    }
+    
+    //重置
+    self.progress = .0f;
+    self.bufferProgress = .0f;
+    self.currentTime = .0f;
+    self.totalTime = .0f;
+    _isSeekWaiting = NO;
+}
+
+#pragma mark - 播放 暂停 下一首 上一首
+/**播放*/
+-(void)df_play{
+    self.state = DFPlayerStatePlaying;
+    [self.player play];
+}
+
+/**暂停*/
+-(void)df_pause{
+    self.state = DFPlayerStatePause;
+    [self.player pause];
+}
+
+/**下一首*/
+- (void)df_next{
+    switch (self.playMode) {
+        case DFPlayerModeOnlyOnce:
+            if (_isNaturalToEndTime) {
+                _isNaturalToEndTime = NO;
+                [self df_pause];
+            }else{
+                [self next];
+            }
+            break;
+        case DFPlayerModeSingleCycle:
+            if (_isNaturalToEndTime) {
+                _isNaturalToEndTime = NO;
+                [self audioPrePlay];
+            }else{
+                [self next];
+            }
+            break;
+        case DFPlayerModeOrderCycle:
+            [self next];
+            break;
+        case DFPlayerModeShuffleCycle:{
+            _playIndex2++;
+            _currentAudioId = [self randomAudioId];
+            self.currentAudioModel = self.playerModelArray[_currentAudioId];
+            [self audioPrePlay];
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+/**上一首*/
+- (void)df_last{
+    if (self.playMode == DFPlayerModeShuffleCycle) {
+        if (_playIndex2 == 1) {
+            _playIndex2 = 0;
+            self.currentAudioModel = self.playerModelArray[_playIndex1];
+        }else{
+            _currentAudioId = [self randomAudioId];
+            self.currentAudioModel = self.playerModelArray[_currentAudioId];
+        }
+        [self audioPrePlay];
+    }else{
+        _currentAudioId--;
+        if (_currentAudioId < 0) {
+            _currentAudioId = self.playerModelArray.count - 1;
+        }
+        self.currentAudioModel = self.playerModelArray[_currentAudioId];
+        [self audioPrePlay];
+    }
+}
+
+- (void)next{
+    _currentAudioId++;
+    if (_currentAudioId < 0 || _currentAudioId >= self.playerModelArray.count) {
+        _currentAudioId = 0;
+    }
+    _playIndex1 = _currentAudioId;
+    _playIndex2 = 0;
+    self.currentAudioModel = self.playerModelArray[_currentAudioId];
+    [self audioPrePlay];
+}
+
+
+#pragma mark - 随机播放相关
+
+- (void)updateRandomIndexArray{
+    NSInteger startIndex = 0;
+    NSInteger length = self.playerModelArray.count;
+    NSInteger endIndex = startIndex+length;
+    NSMutableArray *arr = [NSMutableArray arrayWithCapacity:length];
+    NSMutableArray *arr1 = [NSMutableArray arrayWithCapacity:length];
+    for (NSInteger i = startIndex; i < endIndex; i++) {
+        @autoreleasepool {
+            NSString *str = [NSString stringWithFormat:@"%ld",(long)i];
+            [arr1 addObject:str];
+        }
+    }
+    for (NSInteger i = startIndex; i < endIndex; i++) {
+        @autoreleasepool {
+            int index = arc4random()%arr1.count;
+            int radom = [arr1[index] intValue];
+            NSNumber *num = [NSNumber numberWithInt:radom];
+            [arr addObject:num];
+            [arr1 removeObjectAtIndex:index];
+        }
+    }
+    _randomIndexArray = [NSMutableArray arrayWithArray:arr];
+}
+
+- (NSInteger)randomAudioId{
+    _randomIndex++;
+    if (_randomIndex >= self.randomIndexArray.count) {
+        _randomIndex = 0;
+    }
+    if (_randomIndex < 0) {
+        _randomIndex = self.randomIndexArray.count - 1;
+    }
+    NSInteger index = [self.randomIndexArray[_randomIndex] integerValue];
+    //去重
+    if (index == _currentAudioId) {
+        index = [self randomAudioId];
+    }
+    return index;
+}
+
+#pragma mark - setter
+
+- (void)setCategory:(AVAudioSessionCategory)category{
+    [[AVAudioSession sharedInstance] setCategory:category error:nil];
+}
+
+- (void)setPlayerItem:(AVPlayerItem *)playerItem{
+    if (_playerItem == playerItem) {
+        return;
+    }
+    if (_playerItem) {
+        [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
+        [_playerItem removeObserver:self forKeyPath:DFStatusKey];
+        [_playerItem removeObserver:self forKeyPath:DFLoadedTimeRangesKey];
+        [_playerItem removeObserver:self forKeyPath:DFPlaybackBufferEmptyKey];
+        [_playerItem removeObserver:self forKeyPath:DFPlaybackLikelyToKeepUpKey];
+    }
+    _playerItem = playerItem;
+    if (playerItem) {
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(df_playerDidPlayToEndTime:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
+        [playerItem addObserver:self forKeyPath:DFStatusKey options:NSKeyValueObservingOptionNew context:nil];
+        [playerItem addObserver:self forKeyPath:DFLoadedTimeRangesKey options:NSKeyValueObservingOptionNew context:nil];
+        [playerItem addObserver:self forKeyPath:DFPlaybackBufferEmptyKey options:NSKeyValueObservingOptionNew context:nil];
+        [playerItem addObserver:self forKeyPath:DFPlaybackLikelyToKeepUpKey options:NSKeyValueObservingOptionNew context:nil];
+    }
+}
+
+#pragma mark - 缓存相关
+- (NSString *)df_cachePath:(NSURL *)audioUrl{
+    if ([DFPlayerTool isLocalAudio:audioUrl] || ![DFPlayerTool isNSURL:audioUrl] || !audioUrl) {
+        return nil;
+    }
+    return [DFPlayerFileManager df_cachePath:audioUrl];
+}
+
+- (CGFloat)df_cacheSize:(BOOL)currentUser{
+    return [DFPlayerFileManager df_cacheSize:currentUser];
+}
+
+- (BOOL)df_clearAudioCache:(NSURL *)audioUrl{
+    return [DFPlayerFileManager df_clearAudioCache:audioUrl];
+}
+
+- (BOOL)df_clearUserCache:(BOOL)currentUser{
+    return [DFPlayerFileManager df_clearUserCache:currentUser];
+}
+
+
+#pragma mark - 统一状态代理
+- (void)df_getStatusCode:(NSUInteger)statusCode{
+    dispatch_async(dispatch_get_main_queue(), ^{
+        if (self.delegate && [self.delegate respondsToSelector:@selector(df_player:didGetStatusCode:)]) {
+            [self.delegate df_player:self didGetStatusCode:statusCode];
+        }
+    });
+}
+
+@end
+
+
+

+ 45 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerModel.h

@@ -0,0 +1,45 @@
+//
+//  DFPlayerModel.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/18.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ 音频数据model类(必传)
+ */
+@interface DFPlayerModel : NSObject
+
+@property (nonatomic, assign) NSUInteger audioId; // 音频Id(必须从0开始,仅标识当前音频在数组中的位置)
+
+@property (nonatomic, strong) NSURL *audioUrl; // 音频地址
+
+@end
+
+/**
+ 音频信息model类(非必传)
+ */
+@interface DFPlayerInfoModel : NSObject
+
+@property (nonatomic, nullable, copy) NSString *audioLyrics; // 歌词
+
+/* 正确传入以下属性时,DFPlayer将自动设置锁屏模式和控制中心的播放信息展示 */
+
+@property (nonatomic, nullable, copy) NSString *audioName; // 音频名
+
+@property (nonatomic, nullable, copy) NSString *audioAlbum; // 专辑名
+
+@property (nonatomic, nullable, copy) NSString *audioSinger; // 歌手名
+
+@property (nonatomic, nullable, copy) UIImage *audioImage; // 音频配图
+
+@end
+
+NS_ASSUME_NONNULL_END
+

+ 18 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerModel.m

@@ -0,0 +1,18 @@
+//
+//  DFPlayerModel.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/18.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerModel.h"
+
+@implementation DFPlayerModel
+
+@end
+
+@implementation DFPlayerInfoModel
+
+@end
+

+ 202 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerUIManager.h

@@ -0,0 +1,202 @@
+//
+//  DFPlayerUIManager.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/20.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ DFPlayer控制管理器
+ */
+@interface DFPlayerUIManager : NSObject
+
+/**
+ 单利
+ */
++ (DFPlayerUIManager *)sharedManager;
+
+/**
+ 停止所有进度类控件的刷新
+ */
+- (void)df_stopUpdate;
+
+/**
+ 恢复所有进度类控件的刷新
+ */
+- (void)df_resumeUpdate;
+
+/**
+ 播放暂停按钮
+ 
+ @param frame 按钮frame
+ @param playImage 播放状态时显示的image
+ @param pauseImage 暂停播放时显示的image
+ @param superView 按钮父视图
+ @param block 按钮action
+ @return 播放暂停按钮
+ */
+- (UIButton *)df_playPauseBtnWithFrame:(CGRect)frame
+                             playImage:(UIImage *)playImage
+                            pauseImage:(UIImage *)pauseImage
+                             superView:(UIView *)superView
+                                 block:(nullable void (^)(void))block;
+
+/**
+ 上一首按钮
+ 
+ @param frame 按钮frame
+ @param image 按钮image
+ @param superView 按钮父视图
+ @param block 按钮action
+ @return 上一首按钮
+ */
+- (UIButton *)df_lastBtnWithFrame:(CGRect)frame
+                            image:(UIImage *)image
+                        superView:(UIView *)superView
+                            block:(nullable void (^)(void))block;
+
+/**
+ 下一首按钮
+ 
+ @param frame 按钮frame
+ @param image 按钮image
+ @param superView 按钮父视图
+ @param block 按钮action
+ @return 下一首按钮
+ */
+- (UIButton *)df_nextBtnWithFrame:(CGRect)frame
+                            image:(UIImage *)image
+                        superView:(UIView *)superView
+                            block:(nullable void (^)(void))block;
+
+/**
+ 播放模式按钮(DFPlayerMode不是DFPlayerModeOnlyOnce时有效。)
+ 
+ @param frame 按钮frame
+ @param singleImage 按钮singleImage
+ @param circleImage 按钮circleImage
+ @param shuffleImage 按钮shuffleImage
+ @param superView 按钮父视图
+ @param block 按钮action,若无其他操作需求,传nil即可
+ @return 播放模式按钮
+ */
+- (UIButton *)df_typeBtnWithFrame:(CGRect)frame
+                      singleImage:(UIImage *)singleImage
+                      circleImage:(UIImage *)circleImage
+                     shuffleImage:(UIImage *)shuffleImage
+                        superView:(UIView *)superView
+                            block:(nullable void (^)(void))block;
+
+/**
+ 缓冲条
+ 
+ @param frame frame
+ @param trackTintColor 未缓冲部分进度条颜色
+ @param progressTintColor 已缓冲部分进度条颜色
+ @param superView 进度条父视图
+ @return 进度条
+ */
+- (UIProgressView *)df_bufferViewWithFrame:(CGRect)frame
+                            trackTintColor:(UIColor *)trackTintColor
+                         progressTintColor:(UIColor *)progressTintColor
+                                 superView:(UIView *)superView;
+
+/**
+ 播放进度条
+ 
+ @param frame frame
+ @param minimumTrackTintColor 滑块左边滑动条的颜色
+ @param maximumTrackTintColor 滑块右边滑动条的颜色
+ @param trackHeight 滑动条的高度(长度采用frame的width)
+ @param thumbImage 滑块图片
+ @param superView 进度条父视图
+ @return 进度条
+ */
+- (UISlider *)df_sliderWithFrame:(CGRect)frame
+           minimumTrackTintColor:(UIColor *)minimumTrackTintColor
+           maximumTrackTintColor:(UIColor *)maximumTrackTintColor
+                     trackHeight:(CGFloat)trackHeight
+                      thumbImage:(UIImage *)thumbImage
+                       superView:(UIView *)superView;
+
+/**
+ 音频当前时间label
+ 
+ @param frame frame
+ @param textColor textColor
+ @param textAlignment textAlignment
+ @param font font
+ @param superView label父视图
+ @return label
+ */
+- (UILabel *)df_currentTimeLabelWithFrame:(CGRect)frame
+                                textColor:(UIColor *)textColor
+                            textAlignment:(NSTextAlignment)textAlignment
+                                     font:(UIFont *)font
+                                superView:(UIView *)superView;
+
+/**
+ 音频总时长label
+ 
+ @param frame frame
+ @param textColor textColor
+ @param textAlignment textAlignment
+ @param font font
+ @param superView label父视图
+ @return label
+ */
+- (UILabel *)df_totalTimeLabelWithFrame:(CGRect)frame
+                              textColor:(UIColor *)textColor
+                          textAlignment:(NSTextAlignment)textAlignment
+                                   font:(UIFont *)font
+                              superView:(UIView *)superView;
+
+/**
+ 歌词tableview
+ ①采用lrc标准格式编写,即"[00:00.00]歌词" 或 "[00:00]歌词" 或 "[00:00:00]歌词"
+ ②根据lrc歌词软件开发标准,凡具有“[*:*]”形式的都应认为是标签(注意:其中的冒号并非全角字符“:”)。凡是标签都不应显示。
+ ③支持单句歌词多个时间的格式,如“[00:10.00][00:50.00][00:70.00]歌词”
+ ④lrc歌词文件单行只有时间标签,没有歌词内容的,将被认作为上一个相邻时间内歌词的结束时间,并不做空行显示处理。比如
+ [00:11.11]歌词
+ [00:22.22] (22秒22毫米,该时间下无歌词显示,将被认作为上一个相邻时间歌词的演唱结束时间。此处的相邻不是位置的相邻,而是时间大小的相邻)
+ ⑤如果歌词中需要空行,DFPlayer默认时间标签后的“####”是空行标志,如“[00:11.11]####”,DFPlayer将在解析到歌词为####时做空行显示
+ 详情查看demo中”许嵩(Vae)-有何不可.lrc“文件
+ ⑥DFPlayer认为每个时间标签都是一个单元格。只不过时间标签后无歌词时,DFPlayer将该单元格隐藏。
+ ⑦DFPlayer不对单句歌词做换行处理,所以单行歌词长度尽量不要超过tableview的宽度,当超出时,DFPlayer用末尾省略号处理。
+ 
+ @param frame  tableview frame
+ @param cellRowHeight  tableview 单行rowHeight
+ @param cellBackgroundColor cell背景色
+ @param currentLineLrcForegroundTextColor 当前行歌词文字前景色(此属性不为nil时,采用卡拉OK模式显示)
+ @param currentLineLrcBackgroundTextColor 当前行歌词文字背景色
+ @param otherLineLrcBackgroundTextColor 其他行歌词文字颜色
+ @param currentLineLrcFont 当前行歌词字体
+ @param otherLineLrcFont 其他行歌词字体
+ @param superView 父视图
+ @param block 返回当前正在播放的歌词
+ @return 歌词tableView
+ */
+
+- (UITableView *)df_lyricTableViewWithFrame:(CGRect)frame
+                              cellRowHeight:(CGFloat)cellRowHeight
+                        cellBackgroundColor:(UIColor *)cellBackgroundColor
+          currentLineLrcForegroundTextColor:(nullable UIColor *)currentLineLrcForegroundTextColor
+          currentLineLrcBackgroundTextColor:(UIColor *)currentLineLrcBackgroundTextColor
+            otherLineLrcBackgroundTextColor:(UIColor *)otherLineLrcBackgroundTextColor
+                         currentLineLrcFont:(UIFont *)currentLineLrcFont
+                           otherLineLrcFont:(UIFont *)otherLineLrcFont
+                                  superView:(UIView *)superView
+                                      block:(nullable void (^)(NSString * onPlayingLyrics))block;
+
+
+
+@end
+
+NS_ASSUME_NONNULL_END
+

+ 387 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/DFPlayerUIManager.m

@@ -0,0 +1,387 @@
+//
+//  DFPlayerUIManager.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/20.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerUIManager.h"
+#import "DFPlayer.h"
+#import "DFPlayerTool.h"
+#import "DFPlayerLyricsTableview.h"
+#import <MediaPlayer/MediaPlayer.h>
+
+#pragma mark - DFPlayerSlider
+
+@interface DFPlayerSlider : UISlider
+@property (nonatomic, assign) CGFloat trackHeight;
+@end
+
+@implementation DFPlayerSlider
+
+- (CGRect)trackRectForBounds:(CGRect)bounds{
+    return CGRectMake(0, (CGRectGetHeight(self.frame)-self.trackHeight) / 2, CGRectGetWidth(self.frame), self.trackHeight);
+}
+
+@end
+
+#pragma mark -  DFPlayer控制管理器
+
+//KEY
+NSString * const DFStateKey          = @"state";
+NSString * const DFBufferProgressKey = @"bufferProgress";
+NSString * const DFProgressKey       = @"progress";
+NSString * const DFCurrentTimeKey    = @"currentTime";
+NSString * const DFTotalTimeKey      = @"totalTime";
+
+typedef void(^DFPlayerLyricsBlock)(NSString *onPlayingLyrics);
+
+@interface DFPlayerUIManager() <DFPlayerLyricsTableviewDelegate>
+{
+    BOOL _stopUpdate;
+    BOOL _isSeek;
+}
+
+@property (nonatomic, strong) UIButton          *playBtn;
+@property (nonatomic, strong) UIButton          *typeBtn;
+@property (nonatomic, strong) UIProgressView    *bufferProgressView;
+@property (nonatomic, strong) DFPlayerSlider    *progressSlider;
+@property (nonatomic, strong) UILabel           *currentTimeLabel;
+@property (nonatomic, strong) UILabel           *totalTimeLabel;
+@property (nonatomic, strong) DFPlayerLyricsTableview *lyricsTableView;
+@property (nonatomic, copy) DFPlayerLyricsBlock lyricsBlock;
+
+@property (nonatomic, strong) UIImage *playImage;
+@property (nonatomic, strong) UIImage *pauseImage;
+@property (nonatomic, strong) UIImage *singleImage;
+@property (nonatomic, strong) UIImage *circleImage;
+@property (nonatomic, strong) UIImage *shuffleImage;
+
+@end
+
+@implementation DFPlayerUIManager
+
++ (DFPlayerUIManager *)sharedManager{
+    static DFPlayerUIManager *manager = nil;
+    static dispatch_once_t predicate;
+    dispatch_once(&predicate, ^{
+        manager = [[[self class] alloc] init];
+    });
+    return manager;
+}
+
+- (UIButton *)button:(CGRect)frame
+               image:(UIImage *)image
+           superView:(UIView *)superView
+               block:(nullable void (^)(void))block
+              action:(nullable void(^)(void))action{
+    UIButton *btn = [UIButton buttonWithType:(UIButtonTypeSystem)];
+    btn.frame = frame;
+    [btn setBackgroundImage:image forState:(UIControlStateNormal)];
+    btn.handleButtonActionBlock = ^(UIButton * _Nullable sender) {
+        if (block) {
+            block();
+        }
+        if (action) {
+            action();
+        }
+    };
+    [superView addSubview:btn];
+    return btn;
+}
+
+- (UILabel *)label:(CGRect)frame
+         textColor:(UIColor *)textColor
+     textAlignment:(NSTextAlignment)textAlignment
+              font:(UIFont *)font
+         superView:(UIView *)superView
+       observerKey:(NSString *)observerKey{
+    UILabel *label = [[UILabel alloc] initWithFrame:frame];
+    label.text = @"00:00";
+    label.textColor = textColor;
+    label.textAlignment = textAlignment;
+    label.font = font;
+    [superView addSubview:label];
+    [[DFPlayer sharedPlayer] addObserver:self forKeyPath:observerKey options:NSKeyValueObservingOptionNew context:nil];
+    return label;
+}
+
+- (void)df_stopUpdate{
+    _stopUpdate = YES;
+    self.lyricsTableView.stopUpdate = YES;
+}
+
+- (void)df_resumeUpdate{
+    _stopUpdate = NO;
+    self.lyricsTableView.stopUpdate = NO;
+}
+
+
+#pragma mark - 播放暂停按钮
+- (UIButton *)df_playPauseBtnWithFrame:(CGRect)frame
+                             playImage:(UIImage *)playImage
+                            pauseImage:(UIImage *)pauseImage
+                             superView:(UIView *)superView
+                                 block:(nullable void (^)(void))block{
+    self.playImage = playImage;
+    self.pauseImage = pauseImage;
+    UIImage *img = [DFPlayer sharedPlayer].state == DFPlayerStatePlaying ? self.playImage : self.pauseImage;
+    self.playBtn = [self button:frame image:img superView:superView block:block action:^{
+        if ([DFPlayer sharedPlayer].state == DFPlayerStatePlaying) {
+            [[DFPlayer sharedPlayer] df_pause];
+        }else{
+            [[DFPlayer sharedPlayer] df_play];
+        }
+    }];
+    [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFStateKey options:NSKeyValueObservingOptionNew context:nil];
+    return self.playBtn;
+}
+
+#pragma mark - 上一首按钮
+- (UIButton *)df_lastBtnWithFrame:(CGRect)frame
+                            image:(UIImage *)image
+                        superView:(UIView *)superView
+                            block:(void (^)(void))block{
+    return [self button:frame image:image superView:superView block:block action:^{
+        [[DFPlayer sharedPlayer] df_last];
+    }];
+}
+
+#pragma mark - 下一首按钮
+- (UIButton *)df_nextBtnWithFrame:(CGRect)frame
+                            image:(UIImage *)image
+                        superView:(UIView *)superView
+                            block:(void (^)(void))block{
+    return [self button:frame image:image superView:superView block:block action:^{
+        [[DFPlayer sharedPlayer] df_next];
+    }];
+}
+
+#pragma mark - 播放模式设置按钮
+- (UIButton *)df_typeBtnWithFrame:(CGRect)frame
+                      singleImage:(UIImage *)singleImage
+                      circleImage:(UIImage *)circleImage
+                     shuffleImage:(UIImage *)shuffleImage
+                        superView:(UIView *)superView
+                            block:(void (^)(void))block{
+    
+    if ([DFPlayer sharedPlayer].playMode == DFPlayerModeOnlyOnce) {
+        return nil;
+    }
+    self.singleImage = singleImage;
+    self.circleImage = circleImage;
+    self.shuffleImage = shuffleImage;
+    
+    UIImage *img = [UIImage new];
+    if ([DFPlayer sharedPlayer].playMode == DFPlayerModeSingleCycle) {
+        img = self.singleImage;
+    }else if ([DFPlayer sharedPlayer].playMode == DFPlayerModeOrderCycle){
+        img = self.circleImage;
+    }else{
+        img = self.shuffleImage;
+    }
+    UIButton *btn = [self button:frame image:img superView:superView block:block action:nil];
+    btn.handleButtonActionBlock = ^(UIButton * _Nullable sender) {
+        switch ([DFPlayer sharedPlayer].playMode) {
+            case DFPlayerModeSingleCycle:
+                [DFPlayer sharedPlayer].playMode = DFPlayerModeOrderCycle;
+                [sender setBackgroundImage:self.circleImage forState:(UIControlStateNormal)];
+                break;
+            case DFPlayerModeOrderCycle:
+                [DFPlayer sharedPlayer].playMode = DFPlayerModeShuffleCycle;
+                [sender setBackgroundImage:self.shuffleImage forState:(UIControlStateNormal)];
+                break;
+            case DFPlayerModeShuffleCycle:
+                [DFPlayer sharedPlayer].playMode = DFPlayerModeSingleCycle;
+                [sender setBackgroundImage:self.singleImage forState:(UIControlStateNormal)];
+                break;
+            default:
+                break;
+        }
+    };
+    return btn;
+}
+
+#pragma mark - 音频当前时间
+- (UILabel *)df_currentTimeLabelWithFrame:(CGRect)frame
+                                textColor:(UIColor *)textColor
+                            textAlignment:(NSTextAlignment)textAlignment
+                                     font:(UIFont *)font
+                                superView:(UIView *)superView{
+    self.currentTimeLabel = [self label:frame textColor:textColor textAlignment:textAlignment font:font superView:superView observerKey:DFCurrentTimeKey];
+    return self.currentTimeLabel;
+}
+
+#pragma mark - 音频总时长
+- (UILabel *)df_totalTimeLabelWithFrame:(CGRect)frame
+                              textColor:(UIColor *)textColor
+                          textAlignment:(NSTextAlignment)textAlignment
+                                   font:(UIFont *)font
+                              superView:(UIView *)superView{
+    self.totalTimeLabel = [self label:frame textColor:textColor textAlignment:textAlignment font:font superView:superView observerKey:DFTotalTimeKey];
+    return self.totalTimeLabel;
+}
+
+#pragma mark - 缓冲进度条
+- (UIProgressView *)df_bufferViewWithFrame:(CGRect)frame
+                            trackTintColor:(UIColor *)trackTintColor
+                         progressTintColor:(UIColor *)progressTintColor
+                                 superView:(UIView *)superView{
+    self.bufferProgressView = [[UIProgressView alloc] initWithFrame:frame];
+    self.bufferProgressView.trackTintColor = trackTintColor;
+    self.bufferProgressView.progressTintColor = progressTintColor;
+    [superView addSubview:self.bufferProgressView];
+    [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFBufferProgressKey options:NSKeyValueObservingOptionNew context:nil];
+    return self.bufferProgressView;
+}
+
+#pragma mark - 播放进度条
+- (UISlider *)df_sliderWithFrame:(CGRect)frame
+           minimumTrackTintColor:(UIColor *)minimumTrackTintColor
+           maximumTrackTintColor:(UIColor *)maximumTrackTintColor
+                     trackHeight:(CGFloat)trackHeight
+                      thumbImage:(UIImage *)thumbImage
+                       superView:(UIView *)superView{
+    self.progressSlider = [[DFPlayerSlider alloc] initWithFrame:frame];
+    self.progressSlider.trackHeight = trackHeight;
+    [self.progressSlider setThumbImage:thumbImage forState:UIControlStateNormal];
+    self.progressSlider.minimumValue = 0;
+    self.progressSlider.maximumValue = 1;
+    self.progressSlider.minimumTrackTintColor = minimumTrackTintColor;
+    self.progressSlider.maximumTrackTintColor = maximumTrackTintColor;
+    [superView addSubview:self.progressSlider];
+    
+    [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFProgressKey options:NSKeyValueObservingOptionNew context:nil];
+    
+    //开始滑动
+    [self.progressSlider addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown];
+    //滑动中
+    [self.progressSlider addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
+    //滑动结束
+    [self.progressSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchUpOutside];
+    //点击slider
+    UITapGestureRecognizer *sliderTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapSliderAction:)];
+    [self.progressSlider addGestureRecognizer:sliderTap];
+    return self.progressSlider;
+}
+
+- (void)progressSliderTouchBegan:(UISlider *)sender{
+    _isSeek = YES;
+}
+
+- (void)progressSliderValueChanged:(UISlider *)sender{
+    CGFloat time = [DFPlayer sharedPlayer].totalTime * self.progressSlider.value;
+    [self configTimeLabel:self.currentTimeLabel time:time];
+}
+
+- (void)progressSliderTouchEnded:(UISlider *)sender{
+    [self seek:self.progressSlider.value];
+}
+
+- (void)handleTapSliderAction:(UITapGestureRecognizer *)tap{
+    if ([tap.view isKindOfClass:[UISlider class]]) {
+        _isSeek = YES;
+        UISlider *slider = (UISlider *)tap.view;
+        CGPoint point    = [tap locationInView:slider];
+        CGFloat value    = point.x / slider.frame.size.width;
+        [self seek:value];
+    }
+}
+
+- (void)seek:(CGFloat)value{
+     [[DFPlayer sharedPlayer] df_seekToTime:value completionBlock:^{
+         [[NSNotificationCenter defaultCenter] postNotificationName:DFPlayerNotificationSeekEnd object:nil];
+         self->_isSeek = NO;
+     }];
+}
+
+#pragma mark - KVO
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
+    if (object == [DFPlayer sharedPlayer]) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            if ([keyPath isEqualToString:DFStateKey]) {
+                if (!self->_isSeek) {
+                    UIImage *img = [DFPlayer sharedPlayer].state == (DFPlayerStateBuffering | DFPlayerStatePlaying) ? self.pauseImage : self.playImage;
+                    [self.playBtn setBackgroundImage:img forState:(UIControlStateNormal)];
+                }
+            }else{
+                if (self->_stopUpdate) {
+                    return;
+                }
+                if ([keyPath isEqualToString:DFBufferProgressKey]){
+                    [self.bufferProgressView setProgress:[DFPlayer sharedPlayer].bufferProgress];
+                }else if ([keyPath isEqualToString:DFProgressKey]){
+                    if (!self->_isSeek) {
+                        if (self.progressSlider.state != UIControlStateHighlighted) {
+                            self.progressSlider.value = [DFPlayer sharedPlayer].progress;
+                        }
+                    }
+                }else if ([keyPath isEqualToString:DFCurrentTimeKey]){
+                    if (!self->_isSeek) {
+                        [self configTimeLabel:self.currentTimeLabel time:[DFPlayer sharedPlayer].currentTime];
+                    }
+                }else if ([keyPath isEqualToString:DFTotalTimeKey]){
+                    [self configTimeLabel:self.totalTimeLabel time:[DFPlayer sharedPlayer].totalTime];
+                }
+            }
+        });
+    }
+}
+
+- (void)configTimeLabel:(UILabel *)label time:(CGFloat)time{
+    NSInteger seconds = (NSInteger)time % 60;
+    NSInteger minutes = ((NSInteger)time / 60) % 60;
+    dispatch_async(dispatch_get_main_queue(), ^{
+        label.text = [NSString stringWithFormat:@"%02ld:%02ld",(long)minutes,(long)seconds];
+    });
+}
+
+- (void)dealloc{
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFStateKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFBufferProgressKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFProgressKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFCurrentTimeKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFTotalTimeKey];
+}
+
+#pragma mark - 歌词tableview
+
+- (UITableView *)df_lyricTableViewWithFrame:(CGRect)frame
+                              cellRowHeight:(CGFloat)cellRowHeight
+                        cellBackgroundColor:(UIColor *)cellBackgroundColor
+          currentLineLrcForegroundTextColor:(nullable UIColor *)currentLineLrcForegroundTextColor
+          currentLineLrcBackgroundTextColor:(UIColor *)currentLineLrcBackgroundTextColor
+            otherLineLrcBackgroundTextColor:(UIColor *)otherLineLrcBackgroundTextColor
+                         currentLineLrcFont:(UIFont *)currentLineLrcFont
+                           otherLineLrcFont:(UIFont *)otherLineLrcFont
+                                  superView:(UIView *)superView
+                                      block:(nullable void (^)(NSString * onPlayingLyrics))block{
+    self.lyricsTableView = [[DFPlayerLyricsTableview alloc] init];
+    self.lyricsTableView.frame                             = frame;
+    self.lyricsTableView.backgroundColor                   = cellBackgroundColor;
+    self.lyricsTableView.cellRowHeight                     = cellRowHeight;
+    self.lyricsTableView.cellBackgroundColor               = cellBackgroundColor;
+    self.lyricsTableView.currentLineLrcForegroundTextColor = currentLineLrcForegroundTextColor;
+    self.lyricsTableView.currentLineLrcBackgroundTextColor = currentLineLrcBackgroundTextColor;
+    self.lyricsTableView.otherLineLrcBackgroundTextColor   = otherLineLrcBackgroundTextColor;
+    self.lyricsTableView.currentLineLrcFont                = currentLineLrcFont;
+    self.lyricsTableView.otherLineLrcFont                  = otherLineLrcFont;
+    self.lyricsTableView.lrcTableViewSuperview             = superView;
+    self.lyricsTableView.lyricsDelegate                    = self;
+    [superView addSubview:self.lyricsTableView];
+    if (block) { self.lyricsBlock = block; }
+    return self.lyricsTableView;
+}
+
+- (void)df_lyricsTableview:(DFPlayerLyricsTableview *)lyricsTableview
+           onPlayingLyrics:(NSString *)onPlayingLyrics{
+    if (self.lyricsBlock) {
+        self.lyricsBlock(onPlayingLyrics);
+    }
+}
+
+
+@end
+
+

+ 64 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerFileManager.h

@@ -0,0 +1,64 @@
+//
+//  DFPlayerFileManager.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/**
+ DFPlayer缓存文件管理器
+ */
+@interface DFPlayerFileManager : NSObject
+
++ (void)df_saveUserId:(NSString *)userId;
+
+// 创建临时文件
++ (BOOL)df_createTempFile;
+
+// 往临时文件写入数据
++ (void)df_writeDataToAudioFileTempPathWithData:(NSData *)data;
+
+// 读取临时文件数据
++ (NSData *)df_readTempFileDataWithOffset:(NSUInteger)offset length:(NSUInteger)length;
+
+// 保存临时文件到缓存文件夹
++ (BOOL)df_moveAudioFileFromTempPathToCachePath:(NSURL *)audioUrl;
+
+// 音频缓存路径
++ (NSString *)df_cachePath:(NSURL *)audioUrl;
+
+// 缓存大小
++ (CGFloat)df_cacheSize:(BOOL)currentUser;
+
+// 清除音频缓存
++ (BOOL)df_clearAudioCache:(NSURL *)audioUrl;
+
+// 清除用户缓存
++ (BOOL)df_clearUserCache:(BOOL)currentUser;
+
+@end
+
+static NSMutableDictionary *_archiverDic;
+/**
+ DFPlayer归档管理器
+ */
+@interface DFPlayerArchiverManager : NSObject
+
+// 已经归档的数据
++ (NSMutableDictionary *)df_hasArchivedFileDictionary;
+
+// 归档
++ (BOOL)df_archiveValue:(id)value forKey:(NSString *)key;
+
+// 如果已经归档则删除该路径归档
++ (void)deleteKeyValueIfHaveArchivedWithUrl:(NSURL *)url;
+
+@end
+
+
+
+

+ 155 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerFileManager.m

@@ -0,0 +1,155 @@
+//
+//  DFPlayerFileManager.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerFileManager.h"
+#import "DFPlayerTool.h"
+
+static NSString *DFPlayer_UserId = @"DFPlayerUserId";
+
+static NSString * DFCachePath(BOOL currentUser){
+    // 所有缓存文件都放在了沙盒Cache文件夹下DFPlayerCache文件夹里,然后再根据userId分文件夹缓存
+    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"DFPlayerCache"];
+    if (currentUser) {
+        NSString *userId = [[NSUserDefaults standardUserDefaults] objectForKey:DFPlayer_UserId];
+        NSString *name = [NSString stringWithFormat:@"user_%@",userId];
+        path = [path stringByAppendingPathComponent:name];
+    }
+    
+    if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
+        return path;
+    }
+    BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
+    return success ? path : nil;
+}
+
+static NSString * DFTempPath(){
+    return [NSTemporaryDirectory() stringByAppendingPathComponent:@"MusicTemp.mp4"];
+}
+
+static NSString * DFArchiverPath(){
+    return [DFCachePath(YES) stringByAppendingPathComponent:@"DFPlayer.archiver"];
+}
+
+
+@implementation DFPlayerFileManager
+
++ (void)df_saveUserId:(NSString *)userId{
+    NSString *ids = @"public";
+    if (![userId df_isEmpty]) {
+        ids = userId;
+    }
+    [[NSUserDefaults standardUserDefaults] setObject:ids forKey:DFPlayer_UserId];
+    [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
++ (BOOL)df_createTempFile{
+    NSFileManager *mgr = [NSFileManager defaultManager];
+    NSString *path = DFTempPath();
+    if ([mgr fileExistsAtPath:path]) {
+        [mgr removeItemAtPath:path error:nil];
+    }
+    return [mgr createFileAtPath:path contents:nil attributes:nil];
+}
+
++ (void)df_writeDataToAudioFileTempPathWithData:(NSData *)data{
+    NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:DFTempPath()];
+    [handle seekToEndOfFile];
+    [handle writeData:data];
+}
+
++ (NSData *)df_readTempFileDataWithOffset:(NSUInteger)offset length:(NSUInteger)length{
+    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:DFTempPath()];
+    [handle seekToFileOffset:offset];
+    return [handle readDataOfLength:length];
+}
+
++ (BOOL)df_moveAudioFileFromTempPathToCachePath:(NSURL *)audioUrl{
+    NSString *path = [DFPlayerFileManager audioCachedPath:audioUrl];
+    NSFileManager *mgr = [NSFileManager defaultManager];
+    if (![mgr fileExistsAtPath:path]) {
+        NSNumber *numberId = [NSNumber numberWithInt:[DFPlayer_UserId intValue]];
+        [mgr createDirectoryAtPath:path withIntermediateDirectories:YES attributes:@{NSFileOwnerAccountID:numberId} error:nil];
+    }
+    NSString *audioName = [audioUrl.path lastPathComponent];
+    NSString *cachePath = [path stringByAppendingPathComponent:audioName];
+    NSError *error;
+    BOOL success = [mgr moveItemAtPath:DFTempPath() toPath:cachePath error:&error];
+    if (!success) {//安全性处理 如果没有保存成功,删除归档文件中的对应键值对
+        [DFPlayerArchiverManager deleteKeyValueIfHaveArchivedWithUrl:audioUrl];
+    }
+    return success;
+}
+
++ (NSString *)df_cachePath:(NSURL *)audioUrl{
+    NSString *path = [DFPlayerFileManager audioCachedPath:audioUrl];
+    NSString *audioName = [audioUrl.path lastPathComponent];
+    NSString *cachePath = [path stringByAppendingPathComponent:audioName];
+    return [[NSFileManager defaultManager] fileExistsAtPath:cachePath] ? cachePath : nil;
+}
+
++ (NSString *)audioCachedPath:(NSURL *)audioUrl{
+    NSString *backStr = [[audioUrl.absoluteString componentsSeparatedByString:@"//"].lastObject stringByDeletingLastPathComponent];
+    return [DFCachePath(YES) stringByAppendingPathComponent:backStr];
+}
+
++ (CGFloat)df_cacheSize:(BOOL)currentUser{
+    NSString *path = DFCachePath(currentUser);
+    NSArray *fileArray = [[NSFileManager defaultManager] subpathsAtPath:path];
+    CGFloat size = 0;
+    for (NSString *file in fileArray) {
+        NSString *filePath = [path stringByAppendingPathComponent:file];
+        size += [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil].fileSize;
+    }
+    return size / 1000.0 / 1000.0;
+}
+
++ (BOOL)df_clearAudioCache:(NSURL *)audioUrl{
+    NSString *path = [self df_cachePath:audioUrl];
+    return [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
+}
+
++ (BOOL)df_clearUserCache:(BOOL)currentUser{
+    return [[NSFileManager defaultManager] removeItemAtPath:DFCachePath(currentUser) error:nil];
+}
+
+@end
+
+@implementation DFPlayerArchiverManager
+
++ (NSMutableDictionary *)df_hasArchivedFileDictionary{
+    _archiverDic = [NSKeyedUnarchiver unarchiveObjectWithFile:DFArchiverPath()];
+    if (!_archiverDic){
+        _archiverDic = [NSMutableDictionary dictionary];
+    }
+    return _archiverDic;
+}
+
++ (BOOL)df_archiveValue:(id)value forKey:(NSString *)key{
+    NSMutableDictionary *dic = [DFPlayerArchiverManager df_hasArchivedFileDictionary];
+    [dic setValue:value forKey:key];
+    return [NSKeyedArchiver archiveRootObject:dic toFile:DFArchiverPath()];
+}
+
++ (void)deleteKeyValueIfHaveArchivedWithUrl:(NSURL *)url{
+    NSMutableDictionary *dic = [DFPlayerArchiverManager df_hasArchivedFileDictionary];
+    __block BOOL isHave = NO;
+    [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([key isEqualToString:url.absoluteString]) {
+            [dic removeObjectForKey:key];
+            isHave = YES;
+            *stop = YES;
+        }
+    }];
+    if (isHave) {
+        [NSKeyedArchiver archiveRootObject:dic toFile:DFArchiverPath()];
+    }
+}
+
+@end
+
+

+ 43 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerLyricsTableview.h

@@ -0,0 +1,43 @@
+//
+//  DFPlayerLyricsTableview.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/8/16.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@class DFPlayerLyricsTableview;
+
+@protocol DFPlayerLyricsTableviewDelegate <NSObject>
+
+@optional
+- (void)df_lyricsTableview:(DFPlayerLyricsTableview *)lyricsTableview
+           onPlayingLyrics:(NSString *)onPlayingLyrics;
+
+@end
+
+@interface DFPlayerLyricsTableview : UITableView
+
+@property (nonatomic, weak) id<DFPlayerLyricsTableviewDelegate> lyricsDelegate;
+
+@property (nonatomic, assign) BOOL stopUpdate;
+
+@property (nonatomic, assign) CGFloat cellRowHeight;
+
+@property (nonatomic, strong) UIColor *cellBackgroundColor;
+
+@property (nonatomic, strong) UIColor *currentLineLrcForegroundTextColor;
+
+@property (nonatomic, strong) UIColor *currentLineLrcBackgroundTextColor;
+
+@property (nonatomic, strong) UIColor *otherLineLrcBackgroundTextColor;
+
+@property (nonatomic, strong) UIFont *currentLineLrcFont;
+
+@property (nonatomic, strong) UIFont *otherLineLrcFont;
+
+@property (nonatomic, strong) UIView *lrcTableViewSuperview;
+
+@end

+ 634 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerLyricsTableview.m

@@ -0,0 +1,634 @@
+//
+//  DFPlayerLyricsTableview.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/8/16.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerLyricsTableview.h"
+#import "DFPlayer.h"
+#import "DFPlayerTool.h"
+
+@interface DFPlayerLyricsTableViewCell : UITableViewCell
+
+@property (nonatomic, strong) UILabel *backgroundLrcLabel;
+@property (nonatomic, strong) UILabel *foregroundLrcLabel;
+@property (nonatomic, strong) CALayer *lrcMasklayer;
+
+@end
+
+@implementation DFPlayerLyricsTableViewCell
+
+- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
+    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
+    if (self) {
+        self.backgroundLrcLabel = [[UILabel alloc] init];
+        self.backgroundLrcLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+        self.backgroundLrcLabel.textAlignment = NSTextAlignmentCenter;
+        [self.contentView addSubview:self.backgroundLrcLabel];
+        
+        self.foregroundLrcLabel = [[UILabel alloc] init];
+        self.foregroundLrcLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+        self.foregroundLrcLabel.textAlignment = NSTextAlignmentCenter;
+        [self.contentView addSubview:self.foregroundLrcLabel];
+        
+        self.lrcMasklayer = [CALayer layer];
+        self.lrcMasklayer.anchorPoint = CGPointMake(0, 0.5);
+        self.foregroundLrcLabel.layer.mask = self.lrcMasklayer;
+    }
+    return self;
+}
+@end
+
+static NSString *DFPlayerLyricsStateKey = @"state";
+static NSString *DFPlayerLyricsCurrentTimeKey = @"currentTime";
+static NSString *DFPlayerLyricsCurrentAudioInfoModelKey = @"currentAudioInfoModel";
+static NSString *DFPlayerLyricsConstMark = @"####";
+
+
+@interface DFPlayerLyricsTableview ()
+<UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate>
+{
+    NSIndexPath *_currentIndexPath; // 歌词当前行IndexPath
+    NSIndexPath *_lastIndexPath; // 歌词上一行IndexPath
+    NSInteger _lastIndex; // 歌词上一行标记
+    NSInteger _currentIndex; // 歌词当前行标记
+    CGFloat _timeOffset; // 偏移时间。首次进入和拖拽后设置
+    BOOL _isDraging; // 是否正在拖拽歌词tableView
+    BOOL _isDecelerate; // 拖拽歌词tableView松手后tableView是否还在滚动
+    BOOL _isSeekEnd; // 拖拽进度条是否结束
+}
+// 当前AudioUrl
+@property (nonatomic, strong) NSURL *audioUrl;
+// 时间数组
+@property (nonatomic, strong) NSMutableArray <NSString *> *timeArray;
+// 歌词数组
+@property (nonatomic, strong) NSMutableArray <NSString *> *lyricsArray;
+// 歌词frame数组——currentLineLrcFont
+@property (nonatomic, strong) NSMutableArray *currentLyricsFrameArray;
+// 歌词frame数组——otherLineLrcFont
+@property (nonatomic, strong) NSMutableArray *otherLyricsFrameArray;
+// 解析临时字典
+@property (nonatomic, strong) NSMutableDictionary *tempLrcDictionary;
+// 歌词当前行Index数组
+@property (nonatomic, strong) NSMutableArray *currentIndexArray;
+// 遮罩
+@property (nonatomic, strong) CALayer *maskLayer;
+// 等待恢复行的indexpath
+@property (nonatomic, strong) NSIndexPath *waitResetIndexpath;
+
+@end
+
+@implementation DFPlayerLyricsTableview
+
+- (void)dealloc{
+    [[NSNotificationCenter defaultCenter] removeObserver:DFPlayerNotificationSeekEnd];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFPlayerLyricsStateKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFPlayerLyricsCurrentTimeKey];
+    [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFPlayerLyricsCurrentAudioInfoModelKey];
+}
+
+- (NSMutableArray<NSString *> *)timeArray{
+    if (!_timeArray) {
+        _timeArray = [NSMutableArray array];
+    }
+    return _timeArray;
+}
+
+- (NSMutableArray<NSString *> *)lyricsArray{
+    if (!_lyricsArray) {
+        _lyricsArray = [NSMutableArray array];
+    }
+    return _lyricsArray;
+}
+
+- (NSMutableArray *)currentLyricsFrameArray{
+    if (!_currentLyricsFrameArray) {
+        _currentLyricsFrameArray = [NSMutableArray array];
+    }
+    return _currentLyricsFrameArray;
+}
+
+- (NSMutableArray *)otherLyricsFrameArray{
+    if (!_otherLyricsFrameArray) {
+        _otherLyricsFrameArray = [NSMutableArray array];
+    }
+    return _otherLyricsFrameArray;
+}
+
+- (NSMutableDictionary *)tempLrcDictionary{
+    if (!_tempLrcDictionary) {
+        _tempLrcDictionary = [NSMutableDictionary dictionary];
+    }
+    return _tempLrcDictionary;
+}
+
+- (NSMutableArray *)currentIndexArray{
+    if (!_currentIndexArray) {
+        _currentIndexArray = [NSMutableArray array];
+    }
+    return _currentIndexArray;
+}
+
+- (instancetype)init{
+    self = [super init];
+    if (self) {
+        _isDraging = NO;
+        self.delegate = self;
+        self.dataSource = self;
+        self.separatorStyle = UITableViewCellSeparatorStyleNone;
+        if (@available(iOS 11.0,*)) {
+            self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+        }
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(df_seekEnd) name:DFPlayerNotificationSeekEnd object:nil];
+        
+        NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial;
+        [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFPlayerLyricsCurrentAudioInfoModelKey options:options context:nil];
+        [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFPlayerLyricsCurrentTimeKey options:options context:nil];
+        [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFPlayerLyricsStateKey options:options context:nil];
+    }
+    return self;
+}
+
+- (void)setStopUpdate:(BOOL)stopUpdate{
+    _stopUpdate = stopUpdate;
+    [self df_updateLyricsAnimated:YES];
+}
+
+- (void)df_seekEnd{
+    _isSeekEnd = YES;
+    [self df_updateLyricsAnimated:YES];
+}
+
+#pragma mark - KVO
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
+    if (object == [DFPlayer sharedPlayer]) {
+        if ([keyPath isEqualToString:DFPlayerLyricsCurrentAudioInfoModelKey]){
+            [self df_analyzeLyrics];
+        }else if ([keyPath isEqualToString:DFPlayerLyricsCurrentTimeKey]){
+            [self df_updateLyricsAnimated:YES];
+        }else if ([keyPath isEqualToString:DFPlayerLyricsStateKey]) {
+            if ([DFPlayer sharedPlayer].state == DFPlayerStatePlaying) {
+                [self df_resumeLayer:self.maskLayer];
+            }else{
+                [self df_pauseLayer:self.maskLayer];
+            }
+        }
+    }
+}
+
+#pragma mark - 更新歌词信息
+- (void)df_updateLyricsAnimated:(BOOL)animated{
+    
+    if (self.stopUpdate) {
+        [self df_pauseLayer:self.maskLayer];
+        return;
+    }
+    
+    if (self.timeArray.count <= 0 || self.lyricsArray.count <= 0) {
+        return;
+    }
+    
+    _timeOffset = 0;
+    [self.currentIndexArray removeAllObjects];
+    
+    BOOL scrollAnimated = _isSeekEnd || !animated;
+
+    //获取当前行
+    CGFloat currentTimeFloat = [DFPlayer sharedPlayer].currentTime;
+    NSInteger currentTime = (NSInteger)currentTimeFloat;
+    for (int i = 0; i < self.timeArray.count; i++) {
+        NSInteger time = [self.timeArray[i] integerValue];
+        if (scrollAnimated) {
+            if (currentTime >= time) {
+                _currentIndex = i;
+                //获取偏移时间
+                if (self.currentLineLrcForegroundTextColor) {
+                    _timeOffset = currentTimeFloat - [self.timeArray[i] floatValue];
+                }
+            }
+        }else{
+            if (currentTime == time) {
+                [self.currentIndexArray addObject:[NSString stringWithFormat:@"%d",i]];
+                _currentIndex = i;
+            }
+        }
+        if (time > currentTime) {
+            break;
+        }
+    }
+    
+    if (_lastIndex == _currentIndex) {
+        return;
+    }
+    if (_lastIndex >= 0) {
+        _lastIndexPath = [NSIndexPath indexPathForRow:_lastIndex inSection:0];
+    }
+    _lastIndex = _currentIndex;
+    _currentIndexPath = [NSIndexPath indexPathForRow:_currentIndex inSection:0];
+    if (_isSeekEnd) {//进度回滚,恢复正在播放的当前行
+        [self setOtherLineLyricsTextStatus:_currentIndexPath];
+    }
+
+    //返回当前行歌词
+    if (self.lyricsDelegate && [self.lyricsDelegate respondsToSelector:@selector(df_lyricsTableview:onPlayingLyrics:)]) {
+        NSString *lyrics = self.lyricsArray[_currentIndex];
+        if ([lyrics isEqualToString:DFPlayerLyricsConstMark]) {
+            lyrics = @"";
+        }
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self.lyricsDelegate df_lyricsTableview:self onPlayingLyrics:lyrics];
+        });
+    }
+
+    //当前行移动到中间
+    [self df_scrollPositionMiddleAnimated:!scrollAnimated];
+    
+    //刷新当前行
+    [self updateLyricsAnimated:animated];
+}
+
+- (void)updateLyricsAnimated:(BOOL)animated{
+
+    //同一分同一秒(只有毫秒数不同时)有两句以上歌词
+    if (self.currentIndexArray.count > 1) {
+        for (int i = 0; i < self.currentIndexArray.count-1; i++) {
+            NSInteger index = [self.currentIndexArray[i] integerValue];
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+            dispatch_async(dispatch_get_main_queue(), ^{
+                DFPlayerLyricsTableViewCell *cell = (DFPlayerLyricsTableViewCell *)[self cellForRowAtIndexPath:indexPath];
+                cell.foregroundLrcLabel.hidden = YES;
+                [self setCurrentLineLyricsTextStatus:cell.backgroundLrcLabel
+                                           textColor:self.currentLineLrcForegroundTextColor ? : self.currentLineLrcBackgroundTextColor];
+            });
+            [self performSelector:@selector(setOtherLineLyricsTextStatus:) withObject:indexPath afterDelay:0.2];
+        }
+    }
+
+    dispatch_async(dispatch_get_main_queue(), ^{
+        //当前行
+        DFPlayerLyricsTableViewCell *cell = (DFPlayerLyricsTableViewCell *)[self cellForRowAtIndexPath:self->_currentIndexPath];
+
+        if (!self->_isSeekEnd) {
+            //如果当前行无歌词,记录位置并返回
+
+            NSString *lyrics = [cell.foregroundLrcLabel.text df_removeEmpty];
+
+            if ([lyrics df_isEmpty] || [lyrics isEqualToString:DFPlayerLyricsConstMark]) {
+                if (self.waitResetIndexpath) {
+
+                    [self setOtherLineLyricsTextStatus:self.waitResetIndexpath];
+                }
+                self.waitResetIndexpath = self->_lastIndexPath;
+                return;
+            }
+        }
+        self->_isSeekEnd = NO;
+
+        //设置其他行
+        [self setOtherLineLyricsTextStatus:self->_lastIndexPath];
+        
+        //还原等待恢复行
+        if (self.waitResetIndexpath) {
+            [self setOtherLineLyricsTextStatus:self.waitResetIndexpath];
+            self.waitResetIndexpath = nil;
+        }
+
+        //设置当前行
+        cell.foregroundLrcLabel.hidden = !self.currentLineLrcForegroundTextColor;
+
+        [self setCurrentLineLyricsTextStatus:cell.backgroundLrcLabel
+                                   textColor:self.currentLineLrcBackgroundTextColor];
+        
+        
+        //如果是卡拉OK模式
+        if (self.currentLineLrcForegroundTextColor) {
+            [self setCurrentLineLyricsTextStatus:cell.foregroundLrcLabel
+                                       textColor:self.currentLineLrcForegroundTextColor];
+            
+            cell.lrcMasklayer.position          = CGPointMake(0, self.cellRowHeight/2);
+            cell.lrcMasklayer.bounds            = CGRectMake(0, 0, 0, self.cellRowHeight);
+            cell.lrcMasklayer.backgroundColor   = [UIColor whiteColor].CGColor;
+            self.maskLayer                      = cell.lrcMasklayer;
+            
+            if (self.timeArray.count == 0 || self.lyricsArray.count == 0) {//安全性判断
+                return;
+            }
+            
+            CGFloat duration = 0;
+            if (self->_currentIndex < self.timeArray.count - 1) {
+                duration = fabsf([self.timeArray[self->_currentIndex+1] floatValue]-[self.timeArray[self->_currentIndex] floatValue]);
+            }else{//最后一句歌词
+                if (![self.lyricsArray.lastObject df_isEmpty]) {//如果最后一句不为空
+                    duration = fabs([DFPlayer sharedPlayer].totalTime - [self.timeArray[self->_currentIndex] floatValue]-0.2);
+                }
+            }
+            if (duration != 0) {
+                CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size.width"];
+                NSNumber *end = [NSNumber numberWithFloat:CGRectGetWidth(cell.foregroundLrcLabel.frame)];
+                anim.values = @[@(0),end];
+                anim.keyTimes = @[@(0),@(1)];
+                anim.duration = duration;
+                anim.timeOffset = self->_timeOffset;
+                anim.calculationMode = kCAAnimationLinear;
+                anim.fillMode = kCAFillModeForwards;
+                anim.removedOnCompletion = NO;
+                anim.autoreverses = NO;
+                [self.maskLayer addAnimation:anim forKey:@"Animation"];
+                if (!animated) {
+                    self.maskLayer.speed = 0.0;
+                }
+            }
+        }
+    });
+}
+
+// 设置当前行歌词状态
+- (void)setCurrentLineLyricsTextStatus:(UILabel *)label textColor:(UIColor *)textColor{
+    label.textColor = textColor;
+    label.font = self.currentLineLrcFont;
+    label.frame = [self.currentLyricsFrameArray[_currentIndexPath.row] CGRectValue];
+}
+
+// 设置其他行歌词状态
+- (void)setOtherLineLyricsTextStatus:(id)value{
+    NSIndexPath *indexPath = (NSIndexPath *)value;
+    DFPlayerLyricsTableViewCell *cell = (DFPlayerLyricsTableViewCell *)[self cellForRowAtIndexPath:indexPath];
+    [self setOtherLineLyricsTextStatus:cell indexPath:indexPath];
+}
+
+- (void)setOtherLineLyricsTextStatus:(DFPlayerLyricsTableViewCell *)cell indexPath:(NSIndexPath *)indexPath{
+    if (indexPath.row >= self.otherLyricsFrameArray.count) {
+        return;
+    }
+    cell.foregroundLrcLabel.hidden = YES;
+    cell.backgroundLrcLabel.textColor = self.otherLineLrcBackgroundTextColor;
+    cell.backgroundLrcLabel.font = self.otherLineLrcFont;
+    cell.backgroundLrcLabel.frame = [self.otherLyricsFrameArray[indexPath.row] CGRectValue];
+}
+
+// cell移动到当前行歌词
+- (void)df_scrollPositionMiddleAnimated:(BOOL)animated{
+    if (!_isDraging && _currentIndex < self.lyricsArray.count) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [self scrollToRowAtIndexPath:self->_currentIndexPath
+                        atScrollPosition:(UITableViewScrollPositionMiddle)
+                                animated:animated];
+        });
+    }
+}
+
+// 暂停恢复
+-(void)df_pauseLayer:(CALayer*)layer{
+    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
+    layer.speed = 0.0;
+    layer.timeOffset = pausedTime;
+}
+-(void)df_resumeLayer:(CALayer*)layer{
+    CFTimeInterval pausedTime = [layer timeOffset];
+    layer.speed = 1.0;
+    layer.timeOffset = 0.0;
+    layer.beginTime = 0.0;
+    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
+    layer.beginTime = timeSincePause;
+}
+
+#pragma mark  - tableview
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
+    return self.lyricsArray.count;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
+    return [self.otherLyricsFrameArray[indexPath.row] CGRectValue].size.height;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
+    NSString *identifier = [NSString stringWithFormat:@"DFPLayerLyricsTableViewCell%ld%ld", (long)indexPath.section, (long)indexPath.row];
+    DFPlayerLyricsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
+    if (!cell) {
+        cell = [[DFPlayerLyricsTableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:identifier];
+        cell.backgroundColor = self.cellBackgroundColor;
+        cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    }
+    
+    
+    if (indexPath == _currentIndexPath) {//当前行
+        cell.foregroundLrcLabel.hidden = YES;
+        [self setCurrentLineLyricsTextStatus:cell.backgroundLrcLabel
+                                   textColor:self.currentLineLrcForegroundTextColor ? : self.currentLineLrcBackgroundTextColor];
+    }else{//其他行
+        if (indexPath == self.waitResetIndexpath) {
+            cell.foregroundLrcLabel.hidden = YES;
+            cell.backgroundLrcLabel.textColor = self.currentLineLrcForegroundTextColor ? : self.currentLineLrcBackgroundTextColor;
+            cell.backgroundLrcLabel.font = self.currentLineLrcFont;
+            cell.backgroundLrcLabel.frame = [self.currentLyricsFrameArray[indexPath.row] CGRectValue];
+        }else{
+            [self setOtherLineLyricsTextStatus:cell indexPath:indexPath];
+        }
+    }
+    
+    if (indexPath.row < self.lyricsArray.count) {//安全性判断
+        NSString *lrc = self.lyricsArray[indexPath.row];
+        cell.hidden = [lrc df_isEmpty];
+        if([[lrc df_removeEmpty] isEqualToString:DFPlayerLyricsConstMark]){
+            lrc = @"";
+        }
+        cell.foregroundLrcLabel.text = cell.backgroundLrcLabel.text = lrc;
+    }
+    return cell;
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
+    
+}
+
+#pragma mark - 歌词解析
+- (void)df_analyzeLyrics{
+    
+    _currentIndexPath = nil;
+    self.waitResetIndexpath = nil;
+    _lastIndex = -1;
+    _currentIndex = -1;
+
+    NSURL *url = [DFPlayer sharedPlayer].currentAudioModel.audioUrl;
+    if ([self.audioUrl.absoluteString isEqualToString:url.absoluteString]) {
+        [self checkLyricsAvailability]; // 没有换新音频时,直接复位
+    }else{
+        [self.tempLrcDictionary removeAllObjects];
+        [self.timeArray removeAllObjects];
+        [self.lyricsArray removeAllObjects];
+        [self.currentLyricsFrameArray removeAllObjects];
+        [self.otherLyricsFrameArray removeAllObjects];
+
+        NSString *lyrics = [DFPlayer sharedPlayer].currentAudioInfoModel.audioLyrics;
+        if (!url || [lyrics df_isEmpty]) { // 不可用时,直接复位
+            [self checkLyricsAvailability];
+            return;
+        }
+        
+        self.audioUrl = url;
+        [self analyzeLyrics:lyrics];//解析歌词
+    }
+}
+
+- (void)analyzeLyrics:(NSString *)lyrics{
+    //将每句歌词分割
+    dispatch_async(DFPlayerDefaultGlobalQueue, ^{
+        NSArray <NSString *> *arr = [lyrics componentsSeparatedByString:@"\n"];
+        [arr enumerateObjectsUsingBlock:^(NSString * _Nonnull lrc, NSUInteger idx, BOOL * _Nonnull stop) {
+            //如果该行为空不继续解析
+            if ([lrc df_isEmpty]) {
+                return;
+            }
+            //开始解析(这里只解析时间信息,不解析音频头部信息,如:ar:ti:等)
+            NSArray *lineArray = [NSArray array];
+            if ([lrc rangeOfString:@"]"].location != NSNotFound) {
+                lineArray = [lrc componentsSeparatedByString:@"]"];
+                if (lineArray.count > 2) {//多个时间
+                    NSMutableArray *tempTimeArray = [NSMutableArray array];
+                    for (int j = 0; j < lineArray.count - 1; j++) {
+                        CGFloat seconds = [self getLyricsTime:lineArray[j]];
+                        if (seconds >= 0) {
+                            [tempTimeArray addObject:[NSNumber numberWithFloat:seconds]];
+                        }
+                    }
+                    if (tempTimeArray.count > 0) {
+                        for (NSNumber *number in tempTimeArray) {
+                            [self addObjectWithKey:[number floatValue]
+                                             value:lineArray.lastObject];
+                        }
+                    }
+                }else{//单个时间
+                    CGFloat seconds = [self getLyricsTime:lineArray.firstObject];
+                    if (seconds >= 0) {
+                        [self addObjectWithKey:seconds
+                                         value:lineArray.lastObject];
+                    }
+                }
+            }
+        }];
+        
+        //排序
+        [self.timeArray addObjectsFromArray:self.tempLrcDictionary.allKeys];
+        [self.timeArray sortUsingComparator: ^NSComparisonResult (NSString *str1, NSString *str2) {
+            return [str1 floatValue] > [str2 floatValue];
+        }];
+        for (NSString *key in self.timeArray) {
+            [self.lyricsArray addObject:[self.tempLrcDictionary valueForKey:key]];
+        }
+        
+        //提前计算每句歌词的frame
+        [self getLyricsFrameArray];
+        
+        //重置
+        [self checkLyricsAvailability];
+        
+        //得到数据调用一次更新信息
+        [self df_updateLyricsAnimated:NO];
+    });
+}
+
+// 检查是否有可用歌词。有则移动到首行
+- (void)checkLyricsAvailability{
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self reloadData];
+        if (self.lyricsArray && self.lyricsArray.count > 0) {
+            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
+            [self scrollToRowAtIndexPath:indexPath atScrollPosition:(UITableViewScrollPositionTop) animated:NO];
+        }
+    });
+}
+
+// 时间转换
+- (CGFloat)getLyricsTime:(NSString *)time{
+    if ([time df_isContainLetter]) {
+        return -1;
+    }
+    if ([time rangeOfString:@"["].location != NSNotFound) {
+        time = [[time componentsSeparatedByString:@"["].lastObject df_removeEmpty];
+    }
+    //时间转换成秒
+    CGFloat second = -1.0;
+    //[00:00.00]和[00:00:00](分钟:秒.毫秒)
+    
+    if (time.length == 8) {
+        NSString *str = [time substringWithRange:NSMakeRange(5, 1)];
+        if ([str isEqualToString:@":"]) {
+            time = [time stringByReplacingOccurrencesOfString:@":" withString:@"." options:(NSAnchoredSearch) range:(NSMakeRange(5, 1))];
+        }
+        NSString *minutes = [time substringWithRange:NSMakeRange(0, 2)];
+        NSString *seconds = [time substringWithRange:NSMakeRange(3, 2)];
+        NSString *msec = [time substringWithRange:NSMakeRange(6, 2)];
+        second = minutes.floatValue * 60 + seconds.floatValue + msec.floatValue/1000;
+    }
+    //[00:00](分钟:秒)
+    if (time.length == 6) {
+        NSString *minutes = [time substringWithRange:NSMakeRange(0, 2)];
+        NSString *seconds = [time substringWithRange:NSMakeRange(3, 2)];
+        second = minutes.floatValue * 60 + seconds.floatValue;
+    }
+    return second;
+}
+
+// 加入临时字典
+- (NSMutableDictionary *)addObjectWithKey:(CGFloat)timeKey value:(id)value{
+    NSString *K = [NSString stringWithFormat:@"%lf",timeKey];
+    NSString *V = [NSString stringWithFormat:@"%@",value];
+    [self.tempLrcDictionary setValue:V forKey:K];
+    return self.tempLrcDictionary;
+}
+
+#pragma mark - 计算歌词frame
+- (void)getLyricsFrameArray{
+    [self.lyricsArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            CGRect otherFrame = [self getLyricsFrame:obj font:self.otherLineLrcFont];
+            [self.otherLyricsFrameArray addObject:@(otherFrame)];
+            
+            if (self.currentLineLrcFont == self.otherLineLrcFont) {
+                [self.currentLyricsFrameArray addObject:@(otherFrame)];
+            }else{
+                CGRect currentFrame = [self getLyricsFrame:obj font:self.currentLineLrcFont];
+                [self.currentLyricsFrameArray addObject:@(currentFrame)];
+            }
+        });
+    }];
+}
+
+- (CGRect)getLyricsFrame:(NSString *)lyrics font:(UIFont *)font{
+    if ([lyrics df_isEmpty]) {
+        return CGRectZero;
+    }
+    CGFloat W = [lyrics boundingRectWithSize:(CGSize){MAXFLOAT, self.cellRowHeight}
+                                     options:NSStringDrawingUsesLineFragmentOrigin
+                                  attributes:@{NSFontAttributeName : font}
+                                     context:nil].size.width;
+    W = MIN(W, CGRectGetWidth(self.frame));
+    CGFloat X = (CGRectGetWidth(self.frame) - W) / 2;
+    return (CGRect){X, 0, W, self.cellRowHeight};
+}
+
+#pragma mark - scrollview delegate
+- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
+    _isDraging = YES;
+}
+
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
+    _isDecelerate = decelerate;
+    if (!_isDecelerate) {
+        [self performSelector:@selector(delayToReset) withObject:nil afterDelay:1.25];
+    }
+}
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
+    if (_isDecelerate) {
+        [self performSelector:@selector(delayToReset) withObject:nil afterDelay:1.25];
+    }
+}
+
+- (void)delayToReset{
+    _isDraging = NO;
+    [self df_scrollPositionMiddleAnimated:YES];
+}
+
+@end

+ 66 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerRequestManager.h

@@ -0,0 +1,66 @@
+//
+//  DFPlayerRequestManager.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/31.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <Foundation/NSURLError.h>
+@protocol DFPlayerRequestDelegate <NSObject>
+
+/**
+ 得到服务器响应
+ 
+ @param statusCode 状态码
+ */
+- (void)requestManagerDidReceiveResponseWithStatusCode:(NSInteger)statusCode;
+
+/**
+ 从服务器接收到数据
+ */
+- (void)requestManagerDidReceiveData;
+
+/**
+ 缓存结果
+
+ @param isCached 是否完成了缓存
+ */
+- (void)requestManagerIsCached:(BOOL)isCached;
+
+/**
+ 接收数据完成
+
+ @param errorCode 错误码
+ */
+- (void)requestManagerDidCompleteWithError:(NSInteger)errorCode;
+
+@end
+
+/**
+ DFPlayer请求管理器
+ */
+@interface DFPlayerRequestManager : NSObject
+
++ (instancetype)requestWithUrl:(NSURL *)url;
+
+- (instancetype)initWithUrl:(NSURL *)url;
+
+@property (nonatomic, weak) id<DFPlayerRequestDelegate> delegate;
+
+@property (nonatomic, assign) NSInteger requestOffset;//请求起始位置
+
+@property (nonatomic, assign) NSInteger fileLength;//文件长度
+
+@property (nonatomic, assign) NSInteger cacheLength;//缓冲长度
+
+@property (nonatomic, assign) BOOL cancel;//是否取消请求
+
+@property (nonatomic, assign) BOOL isHaveCache;//是否有缓存
+
+@property (nonatomic, assign) BOOL isObserveFileModifiedTime;//是否观察修改时间
+
+- (void)requestStart;
+
+@end

+ 196 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerRequestManager.m

@@ -0,0 +1,196 @@
+//
+//  DFPlayerRequestManager.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/31.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerRequestManager.h"
+#import "DFPlayerTool.h"
+#import "DFPlayerFileManager.h"
+
+@interface DFPlayerRequestModel : NSObject<NSCoding>
+@property (nonatomic, copy) NSString *last_modified;
+@property (nonatomic, copy) NSString *ETag;
+@end
+
+@implementation DFPlayerRequestModel
+
+- (void)encodeWithCoder:(NSCoder *)aCoder{
+    [aCoder encodeObject:self.last_modified forKey:@"last_modified"];
+    [aCoder encodeObject:self.ETag          forKey:@"ETag"];
+}
+- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
+    self = [super init];
+    if (self) {
+        self.last_modified  = [aDecoder decodeObjectForKey:@"last_modified"];
+        self.ETag           = [aDecoder decodeObjectForKey:@"ETag"];
+    }
+    return self;
+}
+- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
+
+@end
+
+@interface DFPlayerRequestManager()<NSURLSessionDataDelegate>
+
+@property (nonatomic, strong) NSMutableURLRequest   *request;
+@property (nonatomic, strong) NSURLSession          *session;
+@property (nonatomic, strong) NSURLSessionDataTask  *dataTask;
+@property (nonatomic, strong) NSURL                 *requestUrl;
+@property (nonatomic, strong) NSMutableArray        *archiverArray;
+@property (nonatomic, strong) NSOperationQueue      *operationQueue;
+@property (nonatomic, assign) BOOL isNewAudio;
+
+@end
+
+@implementation DFPlayerRequestManager
+
++ (instancetype)requestWithUrl:(NSURL *)url{
+    return [[self alloc] initWithUrl:url];
+}
+
+- (instancetype)initWithUrl:(NSURL *)url{
+    self = [super init];
+    if (self) {
+        
+        [DFPlayerTool startMonitoringNetworkStatus:^(DFPlayerNetworkStatus networkStatus) {
+            if (!self.isNewAudio) {
+                if (networkStatus != DFPlayerNetworkStatusUnknown ||
+                    networkStatus != DFPlayerNetworkStatusNotReachable) {
+                    self.requestOffset = self.cacheLength;
+                    [self resumeRequestStart];
+                }
+            }
+        }];
+        
+        [DFPlayerFileManager df_createTempFile];
+        self.requestUrl = [DFPlayerTool originalURL:url];
+        self.operationQueue = [[NSOperationQueue alloc] init];
+        self.operationQueue.maxConcurrentOperationCount = 1;
+    }
+    return self;
+}
+
+- (void)requestStart{
+    __block DFPlayerRequestModel *model = [[DFPlayerRequestModel alloc] init];
+    if (self.isHaveCache) {//安全性判断。如果沙盒存在缓存文件,再去发起校验。沙盒没有,直接下载缓存
+        if (self.isObserveFileModifiedTime) {
+            NSMutableDictionary *dic = [DFPlayerArchiverManager df_hasArchivedFileDictionary];
+            [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+                if ([key isEqualToString:self.requestUrl.absoluteString]) {
+                    model = (DFPlayerRequestModel *)obj;
+                    *stop = YES;
+                }
+            }];
+        }
+    }
+    
+    self.isNewAudio = YES;
+    //直接请求源端数据
+    self.request = [NSMutableURLRequest requestWithURL:self.requestUrl
+                                           cachePolicy:(NSURLRequestReloadIgnoringCacheData)
+                                       timeoutInterval:10.0];
+    if (model.ETag) {
+        [self.request addValue:model.ETag forHTTPHeaderField:@"If-None-Match"];
+    }
+    if (model.last_modified) {
+        [self.request addValue:model.last_modified forHTTPHeaderField:@"If-Modified-Since"];
+    }
+    [self requestDataTask];
+}
+
+- (void)resumeRequestStart{
+    //直接请求源端数据
+    self.request = [NSMutableURLRequest requestWithURL:self.requestUrl
+                                           cachePolicy:(NSURLRequestReloadIgnoringCacheData)
+                                       timeoutInterval:10.0];
+    if (self.requestOffset > 0) {
+        NSString *value = [NSString stringWithFormat:@"bytes=%ld-%ld", (long)self.requestOffset,(long)self.fileLength];
+        [self.request addValue:value forHTTPHeaderField:@"Range"];
+    }
+    [self requestDataTask];
+}
+
+- (void)requestDataTask{
+    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
+    self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:self.operationQueue];
+    self.dataTask = [self.session dataTaskWithRequest:self.request];
+    [self.dataTask resume];
+}
+
+- (void)setCancel:(BOOL)cancel {
+    _cancel = cancel;
+    [self.dataTask cancel];
+    [self.session invalidateAndCancel];
+}
+
+#pragma mark - NSURLSessionDataDelegate
+//服务器响应
+- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
+    if (_cancel) {
+        return;
+    }
+    completionHandler(NSURLSessionResponseAllow);
+    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+    self.isNewAudio = NO;
+    
+    NSInteger statusCode = httpResponse.statusCode;
+    if (statusCode == 200) {
+        NSString *contentLength = httpResponse.allHeaderFields[@"Content-Length"];
+        self.fileLength = (long)[contentLength integerValue] > 0 ? (long)[contentLength integerValue] : (long)[response expectedContentLength];
+        
+        DFPlayerRequestModel *model = [DFPlayerRequestModel new];
+        model.last_modified = httpResponse.allHeaderFields[@"Last-Modified"];
+        model.ETag          = httpResponse.allHeaderFields[@"Etag"];
+        
+        [DFPlayerArchiverManager df_archiveValue:model forKey:self.requestUrl.absoluteString];
+        
+        //如果没归档成功 如果本地有缓存则还是播放网络文件
+    }else if(statusCode == 206){//带有Range请求头的返回
+        
+    }else{
+        _cancel = YES;
+    }
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(requestManagerDidReceiveResponseWithStatusCode:)]) {
+        [self.delegate requestManagerDidReceiveResponseWithStatusCode:statusCode];
+    }
+    
+}
+
+//服务器返回数据 可能会调用多次
+- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
+    if (_cancel){
+        return;
+    }
+    self.cacheLength += data.length;
+    [DFPlayerFileManager df_writeDataToAudioFileTempPathWithData:data];
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(requestManagerDidReceiveData)]) {
+        [self.delegate requestManagerDidReceiveData];
+    }
+}
+
+//请求完成会调用该方法,请求失败则error有值
+- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
+    if (_cancel) {
+        return;
+    }
+    if (error) {
+        if (self.delegate && [self.delegate respondsToSelector:@selector(requestManagerDidCompleteWithError:)]) {
+            [self.delegate requestManagerDidCompleteWithError:error.code];
+        }
+    }else {
+        self.isNewAudio = YES;
+        //可以缓存则保存文件
+        BOOL success = [DFPlayerFileManager df_moveAudioFileFromTempPathToCachePath:self.requestUrl];
+        if (self.delegate && [self.delegate respondsToSelector:@selector(requestManagerIsCached:)]) {
+            [self.delegate requestManagerIsCached:success];
+        }
+    }
+}
+
+
+@end

+ 42 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerResourceLoader.h

@@ -0,0 +1,42 @@
+//
+//  DFPlayerResourceLoader.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <AVFoundation/AVFoundation.h>
+#import "DFPlayerRequestManager.h"
+#define MimeType @"video/mp4"
+
+@class DFPlayerResourceLoader;
+
+@protocol DFPlayerResourceLoaderDelegate <NSObject>
+
+- (void)loader:(DFPlayerResourceLoader *)loader isCached:(BOOL)isCached;
+
+- (void)loader:(DFPlayerResourceLoader *)loader requestError:(NSInteger)errorCode;
+
+@end
+
+/**
+ DFPlayer资源加载器
+ */
+@interface DFPlayerResourceLoader : NSObject
+<AVAssetResourceLoaderDelegate,DFPlayerRequestDelegate>
+
+@property (nonatomic, weak) id<DFPlayerResourceLoaderDelegate> delegate;
+
+@property (nonatomic, copy) void(^checkStatusBlock)(NSInteger statusCode);
+
+@property (nonatomic, assign) BOOL isCached;// 是否有缓存
+
+@property (nonatomic, assign) BOOL isObserveFileModifiedTime;// 是否观察修改时间
+
+- (void)stopDownload;// 停止下载
+
+@end
+
+

+ 156 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerResourceLoader.m

@@ -0,0 +1,156 @@
+//
+//  DFPlayerResourceLoader.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerResourceLoader.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+#import "DFPlayerFileManager.h"
+
+@interface DFPlayerResourceLoader ()
+
+@property (nonatomic, strong) NSMutableArray<AVAssetResourceLoadingRequest *> *requestList;
+@property (nonatomic, strong) DFPlayerRequestManager *requestManager;
+
+@end
+
+@implementation DFPlayerResourceLoader
+
+- (instancetype)init {
+    if (self = [super init]) {
+        if (_requestList.count >= 0) {
+            [_requestList removeAllObjects];
+        }
+    }
+    return self;
+}
+
+- (NSMutableArray<AVAssetResourceLoadingRequest *> *)requestList{
+    if (!_requestList) {
+        _requestList = [NSMutableArray array];
+    }
+    return _requestList;
+}
+
+- (void)stopDownload{
+    if (self.requestManager) {
+        self.requestManager.cancel = YES;
+    }
+}
+
+#pragma mark - RequestTaskDelegate
+- (void)requestManagerDidReceiveResponseWithStatusCode:(NSInteger)statusCode{
+    if (self.checkStatusBlock) {
+        self.checkStatusBlock(statusCode);
+    }
+}
+- (void)requestManagerDidReceiveData {
+    [self processRequestList];
+}
+- (void)requestManagerIsCached:(BOOL)isCached{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(loader:isCached:)]) {
+        [self.delegate loader:self isCached:isCached];
+    }
+}
+- (void)requestManagerDidCompleteWithError:(NSInteger)errorCode{
+    if (self.delegate && [self.delegate respondsToSelector:@selector(loader:requestError:)]) {
+        [self.delegate loader:self requestError:errorCode];
+    }
+}
+
+#pragma mark - AVAssetResourceLoaderDelegate
+- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
+    [self addLoadingRequest:loadingRequest];
+    return YES;
+}
+
+- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
+    [self.requestList removeObject:loadingRequest];
+}
+
+#pragma mark - 处理LoadingRequest
+- (void)addLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
+    [self.requestList addObject:loadingRequest];
+
+    @synchronized(self) {
+        if (self.requestManager) {
+            long long offset = loadingRequest.dataRequest.requestedOffset;
+            if (offset >= 0 && offset <= self.requestManager.cacheLength) {
+                //数据已经缓存,则直接完
+                [self processRequestList];
+            }else {
+                //数据还没缓存,则等待数据下载;如果是Seek操作,则重新请求
+                [self newTaskWithLoadingRequest:loadingRequest cache:NO];
+            }
+        }else {
+            [self newTaskWithLoadingRequest:loadingRequest cache:YES];
+        }
+    }
+}
+
+- (void)newTaskWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest cache:(BOOL)cache {
+    
+    NSUInteger fileLength = 0;
+    if (self.requestManager) {
+        fileLength = self.requestManager.fileLength;
+        self.requestManager.cancel = YES;
+    }
+    self.requestManager = [[DFPlayerRequestManager alloc] initWithUrl:loadingRequest.request.URL];
+    if (fileLength > 0) {
+        self.requestManager.fileLength = fileLength;
+    }
+    self.requestManager.delegate = self;
+    
+    self.requestManager.isHaveCache = self.isCached;
+    self.requestManager.isObserveFileModifiedTime = self.isObserveFileModifiedTime;
+    
+    [self.requestManager requestStart];
+}
+
+
+- (void)processRequestList {
+    NSMutableArray * finishRequestList = [NSMutableArray array];
+    for (AVAssetResourceLoadingRequest * loadingRequest in self.requestList) {
+        if ([self finishLoadingWithLoadingRequest:loadingRequest]) {
+            [finishRequestList addObject:loadingRequest];
+        }
+    }
+    [self.requestList removeObjectsInArray:finishRequestList];
+}
+
+- (BOOL)finishLoadingWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
+    //填充信息
+    CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(MimeType), NULL);
+    loadingRequest.contentInformationRequest.contentType = CFBridgingRelease(contentType);
+    loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
+    loadingRequest.contentInformationRequest.contentLength = self.requestManager.fileLength;
+    
+    //读文件,填充数据
+    NSUInteger cacheLength = self.requestManager.cacheLength;//已经缓存的数据长度
+    NSUInteger requestedOffset = (long)loadingRequest.dataRequest.requestedOffset;
+    if (loadingRequest.dataRequest.currentOffset != 0) {//如果当前下载长度不为0
+        requestedOffset = (long)loadingRequest.dataRequest.currentOffset;
+    }
+    
+    //当前下载长度-要请求的长度
+    NSUInteger canReadLength = cacheLength - requestedOffset;
+    NSUInteger respondLength = MIN(canReadLength, loadingRequest.dataRequest.requestedLength);
+    
+    [loadingRequest.dataRequest respondWithData:[DFPlayerFileManager df_readTempFileDataWithOffset:requestedOffset length:respondLength]];
+
+    //如果完全响应了所需要的数据,则完成
+    NSUInteger nowendOffset = requestedOffset + canReadLength;
+    NSUInteger reqEndOffset = (long)loadingRequest.dataRequest.requestedOffset + (long)loadingRequest.dataRequest.requestedLength;
+    if (nowendOffset >= reqEndOffset) {
+        [loadingRequest finishLoading];
+        return YES;
+    }
+    return NO;
+}
+
+@end
+
+

+ 75 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerTool.h

@@ -0,0 +1,75 @@
+//
+//  DFPlayerTool.h
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+NS_ASSUME_NONNULL_BEGIN
+
+static NSString * DFPlayerNotificationSeekEnd = @"DFPlayerNotificationSeekEnd";
+
+#define DFPlayerWeakSelf __weak __typeof(&*self) wSelf = self;
+#define DFPlayerStrongSelf __strong __typeof(&*self) sSelf = wSelf;
+
+#define DFPlayerHighGlobalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
+#define DFPlayerDefaultGlobalQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
+
+// 网络状态
+typedef NS_ENUM(NSInteger, DFPlayerNetworkStatus) {
+    DFPlayerNetworkStatusUnknown          = -1, //未知
+    DFPlayerNetworkStatusNotReachable     = 0,  //无网络链接
+    DFPlayerNetworkStatusReachableViaWWAN = 1,  //2G/3G/4G
+    DFPlayerNetworkStatusReachableViaWiFi = 2   //WIFI
+};
+
+/**
+ DFPlayer工具类
+ */
+@interface DFPlayerTool : NSObject
+
+// 链接
++ (NSURL *)customURL:(NSURL *)URL;
++ (NSURL *)originalURL:(NSURL *)URL;
+
+// 是否是本地音频
++ (BOOL)isLocalAudio:(NSURL *)URL;
+
+// 是否是NSURL类型
++ (BOOL)isNSURL:(NSURL *)URL;
+
+// 网络
++ (void)startMonitoringNetworkStatus:(void (^)(DFPlayerNetworkStatus networkStatus))block;
+
++ (void)stopMonitoringNetwork;
+
++ (DFPlayerNetworkStatus)networkStatus;
+
+
+@end
+
+@interface NSString (DFPlayerNSStringExtensions)
+
+// 字符串去空字符
+- (NSString *)df_removeEmpty;
+
+// 判断是否为空
+- (BOOL)df_isEmpty;
+
+// 是否包含字母
+- (BOOL)df_isContainLetter;
+
+@end
+
+@interface UIButton (DFPlayerUIButtonExtensions)
+
+@property(copy, nonatomic) void(^ _Nullable handleButtonActionBlock)(UIButton * _Nullable sender);
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+

+ 128 - 0
创维盒子/双子星云手机/Vendor/DFPlayer/supplement/DFPlayerTool.m

@@ -0,0 +1,128 @@
+//
+//  DFPlayerTool.m
+//  DFPlayer
+//
+//  Created by ihoudf on 2017/7/30.
+//  Copyright © 2017年 ihoudf. All rights reserved.
+//
+
+#import "DFPlayerTool.h"
+#import <objc/runtime.h>
+#import "AFNetworkReachabilityManager.h"
+
+static DFPlayerNetworkStatus _networkStatus;
+
+@implementation DFPlayerTool
+
++ (NSURL *)customURL:(NSURL *)URL{
+    NSString *URLString = [URL absoluteString];
+    if ([URLString rangeOfString:@":"].location != NSNotFound) {
+        NSString *scheme = [[URLString componentsSeparatedByString:@":"] firstObject];
+        if (scheme) {
+            NSString *newScheme = [scheme stringByAppendingString:@"-streaming"];
+            URLString = [URLString stringByReplacingOccurrencesOfString:scheme withString:newScheme];
+            return [NSURL URLWithString:URLString];
+        }else{
+            return nil;
+        }
+    }else{
+        return nil;
+    }
+}
+
++ (NSURL *)originalURL:(NSURL *)URL{
+    NSURLComponents * components = [[NSURLComponents alloc] initWithURL:URL
+                                                resolvingAgainstBaseURL:NO];
+    components.scheme = [components.scheme stringByReplacingOccurrencesOfString:@"-streaming" withString:@""];
+    return [components URL];
+}
+
++ (BOOL)isLocalAudio:(NSURL *)URL{
+    return [URL.absoluteString hasPrefix:@"http"] ? NO : YES;
+}
+
++ (BOOL)isNSURL:(NSURL *)URL{
+    return [URL isKindOfClass:[NSURL class]];
+}
+
++ (void)startMonitoringNetworkStatus:(void (^)(DFPlayerNetworkStatus))block{
+    AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
+    [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
+        switch (status) {
+            case AFNetworkReachabilityStatusUnknown:
+                _networkStatus = DFPlayerNetworkStatusUnknown;
+                break;
+            case AFNetworkReachabilityStatusNotReachable:
+                _networkStatus = DFPlayerNetworkStatusNotReachable;
+                break;
+            case AFNetworkReachabilityStatusReachableViaWWAN:
+                _networkStatus = DFPlayerNetworkStatusReachableViaWWAN;
+                break;
+            case AFNetworkReachabilityStatusReachableViaWiFi:
+                _networkStatus = DFPlayerNetworkStatusReachableViaWiFi;
+                break;
+        }
+        if (block) {
+            block(_networkStatus);
+        }
+    }];
+    [mgr startMonitoring];
+}
+
++ (void)stopMonitoringNetwork{
+    [[AFNetworkReachabilityManager sharedManager] stopMonitoring];
+}
+
++ (DFPlayerNetworkStatus)networkStatus{
+    return _networkStatus;
+}
+
+@end
+
+@implementation NSString (DFPlayerNSStringExtensions)
+
+- (NSString *)df_removeEmpty{
+    NSString *str = [NSString stringWithFormat:@"%@",self];
+    return [str stringByReplacingOccurrencesOfString:@" " withString:@""];
+}
+
+- (BOOL)df_isEmpty{
+    if(!self || [self isEqualToString:@"(null)"] || [self isKindOfClass:[NSNull class]] || [self isEqual:[NSNull null]]){
+        return YES;
+    }
+    return [self df_removeEmpty].length == 0;
+}
+
+- (BOOL)df_isContainLetter{
+    NSRegularExpression *numberRegular = [NSRegularExpression regularExpressionWithPattern:@"[A-Za-z]" options:NSRegularExpressionCaseInsensitive error:nil];
+    NSInteger count = [numberRegular numberOfMatchesInString:self options:NSMatchingReportProgress range:NSMakeRange(0, self.length)];
+    return count > 0;
+}
+
+@end
+
+static NSString * key_ActionBlock = @"key_ActionBlock";
+
+@implementation UIButton(DFPlayerUIButtonExtensions)
+
+- (void)setHandleButtonActionBlock:(void (^)(UIButton * _Nullable))handleButtonActionBlock{
+    objc_setAssociatedObject(self, &key_ActionBlock, handleButtonActionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
+    if (handleButtonActionBlock) {
+        [self addTarget:self action:@selector(actionHandler) forControlEvents:UIControlEventTouchUpInside];
+    }
+}
+
+- (void)actionHandler{
+    if (self.handleButtonActionBlock) {
+        self.handleButtonActionBlock(self);
+    }
+}
+
+- (void (^)(UIButton * _Nullable))handleButtonActionBlock{
+    return objc_getAssociatedObject(self, &key_ActionBlock);
+}
+
+@end
+
+
+