




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、Android多媒體掃描過程(AndroidMediaScannerProcess卜面是系統圖MediaScannerReceiver會在任何的ACTION_BOOT_COMPLETED,ACTION_MEDIA_MOUNTED或ACTION_MEDIA_SCANNER_SCAN_FIL意圖(intent)發出的時候啟動。因為解析媒體文件的元數據或許會需要很長時間,所以MediaScannerReceiver會啟動MediaScannerService。MediaScannerService調用一個公用類MediaScanner去處理真正的工作。MediaScannerReceiver維持兩種
2、掃描目錄:一種是內部卷(internalvolume)指向$(ANDROID_ROOT)/media.另一種是外部卷(externalvolume)指向$(EXTERNAL_STORAGE).掃描和解析工作位于JAVA層和C+層。JAVA層是啟動器。MediaScanner掃描所有目錄,如下步驟:1 .JAVA層初始化在這一步驟中,它會根據目錄是在內部卷還是外部卷打開不同的數據庫。2 .Java層預掃描首先清除文件和播放列表的緩存條目。然后根據MediaProvider返回的請求結果生成新文件和播放列表緩存條目。3 .C+層處理目錄列舉出所有文件和特定的所有子目錄(如果子目錄包含一個.nome
3、dia隱藏文件,則不會被列舉出來。)。被列舉的文件是根據文件擴展來判斷文件是否被支持。如果支持這種文件擴展,C+層就會回調到JAVA層掃描文件。這種擴展就會被掃描到MediaFile.java中列出。下面是支持的文件擴展列表。/*Audio*/addFileType("MP3",FILE_TYPE_MP3,"audio/mpeg");addFileType("M4A",FILE_TYPE_M4A,"audio/mp4");addFileType("WAV",FILE_TYPE_WAV,"
4、;audio/x-wav");addFileType("AMR",FILE_TYPE_AMR,"audio/amr");addFileType("AWB",FILE_TYPE_AWB,"audio/amr-wb");addFileType("WMA",FILE_TYPE_WMA,"audio/x-ms-wma");addFileType("OGG",FILE_TYPE_OGG,"application/ogg");addFil
5、eType("MID",FILE_TYPE_MID,"audio/midi");addFileType("XMF",FILE_TYPE_MID,"audio/midi");addFileType("RTTTL”,FILE_TYPE_MID,"audio/midi");addFileType("SMF",FILE_TYPE_SMF,"audio/sp-midi");addFileType("IMY",FILE_TYPE_IMY&
6、quot;audio/imelody");/*Video*/addFileType("MP4",FILE_TYPE_MP4,"video/mp4");addFileType("M4V",FILE_TYPE_M4V,"video/mp4");addFileType("3GP",FILE_TYPE_3Gppvideo/3gpp");addFileType("3GPP",FILE_TYPE_3GPPvideo/3gpp");addFileType(&q
7、uot;3G2",FILE_TYPE_3GPP2,"videc3gpp2");addFileType("3GPP2",FILE_TYPE_3GPP2,"vide3gpp2");addFileType("WMV",FILE_TYPE_WMV,"video/x-ms-wmv");/*Image*/addFileType("JPG",FILE_TYPE_JPEG,"image/jpeg");addFileType("JPEG",FI
8、LE_TYPE_JPEG,"image/jpeg");addFileType("GIF",FILE_TYPE_GIF,"image/gif");addFileType("PNG",FILE_TYPE_PNG,"image/png");addFileType("BMP",FILE_TYPE_BMP"image/x-ms-bmp");addFileType("WBMP",FILE_TYPE_WBMP"image/vnd.wap.w
9、bmp");/*AudioPlayList*/addFileType("M3U",FILE_TYPE_M3U,"audio/x-mpegurl");addFileType("PLS",FILE_TYPE_PLS,"audio/x-scpls");addFileType("WPL",FILE_TYPE_WPL,"application/vnd.ms-wpl");4 .Java層掃描文件a)Java層開始文件首先它忽如一些MacOS和WindowsMediaPlayer
10、特殊的文件。然后它會查看被掃描的文件是否已經存在于緩存條目中,如果存在,它會檢查文件上次修改的時間是否改變。最后它返回該文件是否需要進一步處理的結果。如果不需要,接下來的兩步不會執行。b)C+層掃描文件不是所有的文件都需要交給C+層解析成元數據。只有下面的文件類型會被解析,注意,這里不處理image文件。if(mFileType=MediaFile.FILE_TYPE_MP3|mFileType=MediaFile.FILE_TYPE_MP4|mFileType=MediaFile.FILE_TYPE_M4A|mFileType=MediaFile.FILE_TYPE_3GPP|mFileTy
11、pe=MediaFile.FILE_TYPE_3GPP2|mFileType=MediaFile.FILE_TYPE_OGG|mFileType=MediaFile.FILE_TYPE_MID|mFileType=MediaFile.FILE_TYPE_WMA)復制代碼對于被解析的元數據信息,C+層會回調到JAVA層白hhandleStringTag。Java層會記錄它的name/value信息。c)Java層結束文件最后根據上一步解析出的值,Java層會更新相應的MeidaProvider產生的數據庫表。5 .Java層發送掃描到目前為止,所有文件已經被掃描,它最后會檢查文件和播放列表緩存條
12、目,看是否所有項仍然存在于文件系統。如果有空條目,則會從數據庫中刪除。這樣它能夠保持數據庫和文件系統的一致性。其他的應用程序通過接收MediaScannerService發出的ACTION_MEDIA_SCANNER_STARTE訝口ACTION_MEDIA_SCANNER_FINISHEDT圖能夠知道什么時候掃描操作開始和結束。MediaScanner之所以拿MediaScanner開刀因為想借用系統的MediaScan工具通過Intent直接調用系統的步驟1 .下載并安裝Git過程略網絡上很多2 .得到該功能的模塊地址并使用Git下載之地址:git:android.git.kernel.o
13、rg/platform/packages/providers/MediaProvider.git3 .分析源代碼:-AndroidManifest.xml:各組件屬性描述文件-MediaProvider:extendsContentProvider使用SQLiteDatabase保存查詢數據action="content:/media"-MediaScannerCursor.java-MediaScannerReceiver:extendsBroadcastReceiver用于接收指定Broadcast:BOOT_COMPLETEDMEDIA_MOUNTEDMEDIA_SC
14、ANNER_SCAN_FIL滸啟動MediaScannerService開始掃描-MediaScannerService:extendsService執行具體的掃描工作-MediaThumbRequest4.鑒于并不打算自行實現多媒體掃描因此此次重點研究對象:MediaScannerReceiver5. MediaScannerReceiver代碼Java代碼1. publicclassMediaScannerReceiverextendsBroadcastReceiver2. (3. privatefinalstaticStringTAG="MediaScannerReceiver
15、"4.5. Override6. publicvoidonReceive(Contextcontext,Intentintent)7. Stringaction=intent.getAction();8. Uriuri=intent.getData();9. StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath();10.11. if(action.equals(Intent.ACTION_BOOT_COMPLETED)12. /scaninternalstorage13. scan(c
16、ontext,MediaProvider.INTERNAL_VOLUME);14. else15. if(uri.getScheme().equals("file")16. /handleintentsrelatedtoexternalstorage17. Stringpath=uri.getPath();18. if(action.equals(Intent.ACTION_MEDIA_MOUNTED)&&19. externalStoragePath.equals(path)20. scan(context,MediaProvider.EXTERNAL_V
17、OLUME);21. elseif(action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)&&22. path!=null&&path.startsWith(externalStoragePath+"/")23. scanFile(context,path);24. 25. 26. 29. privatevoidscan(Contextcontext,Stringvolume)30. Bundleargs=newBundle();31. args.putString("volume&
18、quot;,volume);32. context.startService(33. newIntent(context,MediaScannerService.class).putExtras(args);34. 35.36. privatevoidscanFile(Contextcontext,Stringpath)37. Bundleargs=newBundle();38. args.putString("filepath",path);39. context.startService(40. newIntent(context,MediaScannerService
19、.class).putExtras(args);41. 42. 6 .根據以上代碼得知:-當系統啟動完畢會掃描一次-當ACTION_MEDIA_MOUNTEDACTION_MEDIA_SCANNER_SCAN_FILE也會掃描7 .如何調用系統MediaScanner進行掃描-通過Intent.ACTION_MEDIA_MOUNTED進行全掃描Java代碼1. publicvoidallScan()2. sendBroadcast(newIntent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file:/"3. +Environment.
20、getExternalStorageDirectory();4. -通過Intent.ACTION_MEDIA_SCANNER_SCAN_FILE掃描某個文件Java代碼1. publicvoidfileScan(StringfName)2. Uridata=Uri.parse("file:/"+fName);3. sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data);4. 補充:上述方法是不支持對文件夾的即:Uridata必須是文件的Uri如果是文件夾的其不會起作用的切記!-如何掃描某文件夾
21、下所有文件難道就不可以么?當然不借助于Intent.ACTION_MEDIA_SCANNER_SCAN_FILE我們可以這么做:取出該文件夾下的所有子文件如其是文件且類型符合條件就取出該文件目錄以Intent.ACTION_MEDIA_SCANNER_SCAN_FILE方式發送至MediaScannerReceiver若其為文件夾則迭代查詢之故實現為:Java代碼1. publicvoidfileScan(Stringfile)2. Uridata=Uri.parse("file:/"+file);3.4. Log.d("TAG","file:
22、"+file);5. sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data);6. 7.8. publicvoidfolderScan(Stringpath)9. Filefile=newFile(path);10.11. if(file.isDirectory()12. Filearray=file.listFiles();13.14. for(inti=0;i<array.length;i+)15. Filef=arrayi;16.17. if(f.isFile()/FILETYPE18. St
23、ringname=f.getName();19.20. if(name.contains(".mp3")21. fileScan(f.getAbsolutePath();22. 23. 24. else/FOLDERTYPE25.folderScan(f.getAbsolutePath();26. 27. 28. 29. 8.鑒于多數人并不關心其原理僅關系如何使用故總結如下:-掃描全部我猜測其在效率方面可能有點副作用Java代碼1.publicvoidsystemScan()2.sendBroadcast(newIntent(Intent.ACTION_MEDIA_MOUN
24、TED,Uri.parse("file:/"3.+Environment.getExternalStorageDirectory();4.掃描某個文件參數:填入該文件的路徑Java代碼1.publicvoidfileScan(Stringfile)2.Uridata=Uri.parse("file:/"+file);3.4.sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data);5.-掃描文件夾參數:填入該文件夾路徑Java代碼1.publicvoidfileScan(Str
25、ingfile)2.Uridata=Uri.parse("file:/"+file);3.4.sendBroadcast(newIntent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,data);7.publicvoidfolderScan(Stringpath)8. Filefile=newFile(path);9.10. if(file.isDirectory()11. Filearray=file.listFiles();12.13. for(inti=0;i<array.length;i+)14. Filef=arrayi;1
26、5.16. if(f.isFile()/FILETYPE17. Stringname=f.getName();18.19. if(name.contains(".mp3")20. fileScan(f.getAbsolutePath();21. 22. 23. else/FOLDERTYPE24. folderScan(f.getAbsolutePath();25. 26. 27. 28. 終于結束了看似簡單的東西研究起來還是挺復雜的!AndroidMediaScannerMechanismAnalyzeArchitectureFigure2-1AsFigure2-1.Me
27、diaScannerReciverstartupatanytimewherereceiveintentACTION_BOOT_COMPLETED,ACTION_MEDIA_MOUNTEDorACTION_MEDIA_SCANNER_SCAN_FILE.Causeonthatspendlongtimetoprocessthemediametadata,sothatMediaScannerReceiverwillcallupMediaScannerService.MediaScannerServiceinvokeapublicclasswhichnamedMediaScannertodothesc
28、anwork,MediaScannerhandlethemediadatabasewithapublicclasswhichnamedMediaProviderMediaScannerReciversupporttwotypesofthefolder:1.internalvolume,pointto$(ANDROID_ROOT)/media.2.Externalvolume,point$(EXTERNAL_STORAGE).ScannerActionACTION_BOOT_COMPLETEDpublicstaticfinalStringACTION_BOOT_COMPLETEDBroadcas
29、tAction:Thisisbroadcastonce,afterthesystemhasfinishedbooting.Itcanbeusedtoperformapplication-specificinitialization,suchasinstallingalarms.YoumustholdtheRECEIVE_BOOT_COMPLETEDpermissioninordertoreceivethisbroadcast.Thisisaprotectedintentthatcanonlybesentbythesystem.ConstantValue:"ent
30、.action.BOOT_COMPLETED"ACTION_MEDIA_MOUNTEDpublicstaticfinalStringACTION_MEDIA_MOUNTEDBroadcastAction:Externalmediaispresentandmountedatitsmountpoint.ThepathtothemountpointfortheremovedmediaiscontainedintheIntent.mDatafield.TheIntentcontainsanextrawithname"read-only"andBooleanvaluetoi
31、ndicateifthemediawasmountedreadonly.ConstantValue:"ent.action.MEDIA_MOUNTED"ACTION_MEDIA_SCANNER_SCAN_FILE.publicstaticfinalStringACTION_MEDIA_SCANNER_SCAN_FILEBroadcastAction:Requestthemediascannertoscanafileandaddittothemediadatabase.ThepathtothefileiscontainedintheIntent.mDat
32、afield.ConstantValue:"ent.action.MEDIA_SCANNER_SCAN_FILE"AndroidMediaScannerReceiverWecanfindthesourcefilewithpathanydroid/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.javapublicclassMediaScannerReceiverextendsBroadcastReceiverOverridepub
33、licvoidonReceive(Contextcontext,Intentintent)if(action.equals(Intent.ACTION_BOOT_COMPLETED)/scaninternalstoragescan(context,MediaProvider.INTERNAL_VOLUME);elseif(uri.getScheme().equals("file")/handleintentsrelatedtoexternalstorageStringpath=uri.getPath();if(action.equals(Intent.ACTION_MEDI
34、A_MOUNTED)&&externalStoragePath.equals(path)scan(context,MediaProvider.EXTERNAL_VOLUME);elseif(action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)&&path!=null&&path.startsWith(externalStoragePath+"/")scanFile(context,path);privatevoidscan(Contextcontext,Stringvolum
35、e)Bundleargs=newBundle();args.putString("volume",volume);context.startService(newIntent(context,MediaScannerService.class).putExtras(args);privatevoidscanFile(Contextcontext,Stringpath)Bundleargs=newBundle();args.putString("filepath",path);context.startService(newIntent(context,M
36、ediaScannerService.class).putExtras(args);BroadcasReceiver7MediaScannerHeceiuer+onReceieO:void-scanO:void-scanFileQ:voidFigure4-1Asthesourcecodes,andFigure4-1,therearetwodifferentmediadatabaseinthesystem,istheinternalstorage,theotheristheexternalstorage.Finally,theycallthemethodstartService()tostart
37、theMediaScannerService.AndroidMediaScannerServiceWecanfindthesourcefilewithpath/android/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerService.java.publicvoidonCreate()Threadthr=newThread(null,this,"MediaScannerService");thr.start();publicintonStartCommand(Int
38、entintent,intflags,intstartId)Messagemsg=mServiceHandler.obtainMessage();mServiceHandler.sendMessage(msg);returnService.START_REDELIVER_INTENT;publicvoidrun()mServiceHandler=newServiceHandler();)privatefinalclassServiceHandlerextendsHandler(OverridepublicvoidhandleMessage(Messagemsg)(if(filePath!=nu
39、ll)Uriuri=scanFile(filePath,arguments.getString("mimetype");)elsescan(directories,volume);)privatevoidscan(Stringdirectories,StringvolumeName)MediaScannerscanner=createMediaScanner();scanner.scanDirectories(directories,volumeName);)privateUriscanFile(Stringpath,StringmimeType)MediaScanners
40、canner=createMediaScanner();returnscanner.scanSingleFile(path,volumeName,mimeType);)ServiceHandlerMediaScannerService+handleMessage():void-mBinder:IMediaScannerService.Stub«interface»Runnable- openDatabase():void- closeDatabase():void- createMediaScanner():void- scan():void- scanFile():voi
41、d+onCreate():void+onStart():void+onDestroy():gid+run():void+onBindf):voidFigure5-1Androidapplicationmaybeblockwithinvokingservice,genericcreateathreadtorunatthebackend.First,mediaservicecallonCreate()tostarttheserviceifitisnotexist,thencreateathreadandrunthread.start()tocalltherunnablemethodwhichhas
42、implementedwiththerun().Intherun(),invokeainternalclassnamedServiceHandlertoscanfile.Inthemethodscan()andscanFile(),theyallinvokeapublicclassnamedMediaScannerwhomhasmethodnamedcreateMediaScanner()toprocessmetadataandmediadabase.AndroidMediaScannerWecanfindtherelatefileswithpathandroid/frameworks/bas
43、e/media/java/android/media,Figure6-1javacodesfile:/android/frameworks/base/media/java/android/media/MediaScanner.javapublicvoidscanDirectories(String口directories,StringvolumeName)for(inti=0;i<directories.length;i+)processDirectory(directoriesi,MediaFile.sFileExtensions,mClient);publicvoidscanFile
44、(Stringpath,longlastModified,longfileSize)/Thisisthecallbackfuntionfromnativecodes./Log.v(TAG,"scanFile:"+path);doScanFile(path,null,lastModified,fileSize,false);publicvoidscanFile(Stringpath,StringmimeType,longlastModified,longfileSize)doScanFile(path,mimeType,lastModified,fileSize,false)
45、;publicUridoScanFile(Stringpath,StringmimeType,longlastModified,longfileSize,booleanscanAlways)if(isMetadataSupported(mFileType)processFile(path,mimeType,this);elseif(MediaFile.isImageFileType(mFileType)/weusedtocomputethewidthandheightbutit'snotworthitresult=endFile(entry,ringtones,notification
46、s,alarms,music,podcasts);privateUriendFile(FileCacheEntryentry,booleanringtones,booleannotifications,booleanalarms,booleanmusic,booleanpodcasts)throwsRemoteExceptionmMediaProvider.insert()/mMediaProvider.update()privatenativevoidprocessDirectory(Stringpath,Stringextensions,MediaScannerClientclient);
47、privatenativevoidprocessFile(Stringpath,StringmimeType,MediaScannerClientclient);c+codesfile:/android/frameworks/base/media/jni/android_media_MediaScanner.cppstaticvoidandroid_media_MediaScanner_processDirectory(JNIEnv*env,jobjectthiz,jstringpath,jstringextensions,jobjectclient)MediaScanner*mp=(Medi
48、aScanner*)env->GetIntField(thiz,fields.context);MyMediaScannerClientmyClient(env,client);mp->processDirectory(pathStr,extensionsStr,myClient,ExceptionCheck,env);staticvoidandroid_media_MediaScanner_processFile(JNIEnv*env,jobjectthiz,jstringpath,jstringmimeType,jobjectclient)MediaScanner*mp=(Me
49、diaScanner*)env->GetIntField(thiz,fields.context);MyMediaScannerClientmyClient(env,client);mp->processFile(pathStr,mimeTypeStr,myClient);file:/android/external/opencore/android/mediascanner.cppstatus_tMediaScanner:processDirectory(constchar*path,constchar*extensions,MediaScannerClient&clie
50、nt,ExceptionCheckexceptionCheck,void*exceptionEnv)result=doProcessDirectory(pathBuffer,pathRemaining,extensions,client,exceptionCheck,exceptionEnv);status_tMediaScanner:doProcessDirectory(char*path,intpathRemaining,constchar*extensions,MediaScannerClient&client,ExceptionCheckexceptionCheck,void*
51、exceptionEnv)client.scanFile(path,statbuf.st_mtime,statbuf.st_size);status_tMediaScanner:processFile(constchar*path,constchar*mimeType,MediaScannerClient&client)status_tresult=PVMFSuccess;interror=0;InitializeForThread();OSCL_TRY(error,client.setLocale(mLocale);client.beginFile();/LOGD("pro
52、cessFile%smimeType:%sn",path,mimeType);constchar*extension=strrchr(path,'.');if(extension&&(strcasecmp(extension,".mp3")=0|strcasecmp(extension,".aac")=0)/Bothmp3andaacfilesuseID3tagstoholdmetadataresult=parseID3Tag(path,client);elseif(extension&&(str
53、casecmp(extension,".mp4")=0|strcasecmp(extension,".m4a")=0|strcasecmp(extension,".3gp")=0|strcasecmp(extension,".3gpp")=0|strcasecmp(extension,".3g2")=0|strcasecmp(extension,".m4b")=0|strcasecmp(extension,".3gpp2")=0)result=parseM
54、P4(path,client);elseif(extension&&strcasecmp(extension,".ogg")=0)result=parseOgg(path,client);elseif(extension&&(strcasecmp(extension,".mid")=0|strcasecmp(extension,".smf")=0|strcasecmp(extension,".imy")=0)result=parseMidi(path,client);elseif(e
55、xtension&&(strcasecmp(extension,".wma")=0|strcasecmp(extension,".wmv")=0|strcasecmp(extension,".asf")=0|strcasecmp(extension,".amr")=0|strcasecmp(extension,".wav")=0|strcasecmp(extension,".awb")=0)result=parseASF(path,client);elsere
56、sult=PVMFFailure;client.endFile(););OSCL_FIRST_CATCH_ANY(error,LOGV("OSCL_LEAVEhappenedinprocessFileExitwithfailure");returnPVMFFailure);returnresult;AsFigure6-1,IfscanDirectory()hascalledbyMediaScannerService,itwillinvokec+llibrarylibmedia_jnimethodprocessDiretorys()byJNImechanism,thenpro
57、cessDiretorys()invokeJAVAclassMyMediaScannerClientbyJNI,Finaly,endFile()usetoinsertorupdatethedatabase原文地址修改AndroidMediaScanner的掃描路徑對Android稍有熟悉的人都知道,AndroidMediaScanner只對SD卡上的媒體文件進行掃描。其掃描的策略,請參考«AndroidMediaScannerProcess»o假如我們的硬件平臺上面沒有提供SD卡槽,難道Android就不能進行對媒體文件播放了嗎?當然不是的,否則Android系統將不會成為
58、一個完善的Frameworko本文結合本人的經驗介紹一下,怎樣修改多媒體文件的掃描路徑。根據AndroidMediaScannerProcess»的介紹我們可以知道,Androidscanner掃描媒體完成之后,會把媒體文件存放在數據庫中,由MediaProvider為上層的應用程序提供服務。經過研究Mediascanner的代碼發現,他的掃描路徑為android.os.Environment.EXTERNAL_STORAGE_DIRECTORY定義該變量文件位于:frameworks/base/core/java/android/os/Environment.java默認情況下,A
59、ndroid將會搜索/sddisk目錄:privatestaticfinalFileEXTERNAL_STORAGE_DIRECTORY=getDirectory("EXTERNAL_STORAGE","/sddisk");為了讓其進行搜索我們自定義的路徑,可以修改該變量的定義,加入我們希望掃描/external目錄。代碼修改如下:privatestaticfinalFileEXTERNAL_STORAGE_DIRECTORY=getDirectory("EXTERNAL_STORAGE","/external");這本AAndroidMediaScanner將會搜索/external目錄來查找媒體文件。下一步我們需要保證這個文件一定要存在,我們需要修改init.rc文件。增加如下的定義:mkdir/external0777systemsystem這樣在開機的時候,如果/external目錄不存在,則會創建一個。如果已經存在,則不會有任何動作。另外怎樣觸發MediaScanner?根據Andr
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 農村買房怎樣寫協議合同
- 外貿合同協議模板
- 生產框架協議合同
- 協議保險合同
- 短期聘用合同簡單協議書
- 學校廚房員工合同協議書
- 修建房子協議合同書模板
- 藝人培訓協議合同
- 房屋裝修翻新合同協議書
- 貨物采購合同協議
- 檔案檔案管理基礎知識試題及答案
- 2025-2030中國慢性腰痛治療行業市場現狀供需分析及投資評估規劃分析研究報告
- 演出經紀人與文化經濟試題
- pcb抄板合同范例
- 藥浴療法的基本原理操作規程及臨床應用
- 2025年吉林工業職業技術學院單招職業傾向性測試題庫完整
- 生態農業發展與綠色金融的融合路徑
- 奶茶店應聘簡歷范本
- 附著齦重建在口腔種植修復中的應用探索
- 房屋建造流程過程
- 2025年教科新版七年級英語下冊月考試卷
評論
0/150
提交評論