Repository: wgllss/WXDynamicPlugin Branch: master Commit: cd6bc61159f4 Files: 1527 Total size: 2.4 MB Directory structure: gitextract_2old5cjg/ ├── .gitignore ├── LICENSE ├── README.md ├── WX/ │ ├── WX-Code/ │ │ ├── WX-Host/ │ │ │ ├── app/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ ├── sign/ │ │ │ │ │ └── WXSample.jks │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── assets/ │ │ │ │ │ └── loading_1000 │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── dynamic/ │ │ │ │ │ └── host/ │ │ │ │ │ ├── FaceImpl.kt │ │ │ │ │ ├── SampleApplication.kt │ │ │ │ │ └── VersionImpl.kt │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── ic_launcher_background.xml │ │ │ │ ├── drawable-v24/ │ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ │ └── ic_launcher.xml │ │ │ │ └── xml/ │ │ │ │ ├── backup_rules.xml │ │ │ │ ├── data_extraction_rules.xml │ │ │ │ └── network_security_config.xml │ │ │ └── app-lib/ │ │ │ ├── wgllss-business-re-library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ ├── main/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ └── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── sample/ │ │ │ │ │ └── feature_system/ │ │ │ │ │ └── globle/ │ │ │ │ │ └── Constants.kt │ │ │ │ └── test/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── sample/ │ │ │ │ └── ExampleUnitTest.kt │ │ │ ├── wgllss-common-re-library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── libs/ │ │ │ │ │ └── com_wang_avi_library-2.1.3.aar │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── core/ │ │ │ │ │ ├── dialog/ │ │ │ │ │ │ └── CommonLoadingView.kt │ │ │ │ │ ├── ex/ │ │ │ │ │ │ ├── ContextEX.kt │ │ │ │ │ │ ├── Flow.kt │ │ │ │ │ │ └── NetWorkHelp.kt │ │ │ │ │ ├── permissions/ │ │ │ │ │ │ ├── PermissionInterceptor.kt │ │ │ │ │ │ └── PermissionNameConvert.kt │ │ │ │ │ ├── units/ │ │ │ │ │ │ ├── AppGlobals.kt │ │ │ │ │ │ ├── DeviceIdUtil.kt │ │ │ │ │ │ └── LogTimer.kt │ │ │ │ │ └── widget/ │ │ │ │ │ └── CommonToast.kt │ │ │ │ └── res/ │ │ │ │ ├── anim/ │ │ │ │ │ └── anim_alpha_121.xml │ │ │ │ ├── drawable/ │ │ │ │ │ ├── button_bg_transparent_helf.xml │ │ │ │ │ └── progressbar_shape.xml │ │ │ │ ├── layout/ │ │ │ │ │ └── common_loading.xml │ │ │ │ └── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── wgllss-dynamic-host-library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── consumer-rules.pro │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ ├── androidTest/ │ │ │ │ │ └── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── host/ │ │ │ │ │ └── library/ │ │ │ │ │ └── ExampleInstrumentedTest.kt │ │ │ │ ├── main/ │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── test/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── host/ │ │ │ │ └── library/ │ │ │ │ └── ExampleUnitTest.kt │ │ │ └── wgllss-dynamic-host-skin-resource-lib/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── splash_preview.xml │ │ │ │ └── splash_preview_dark.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ └── WX-Plugin/ │ │ ├── Wgllss-Dynamic-Plugin-Common-Library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── core/ │ │ │ ├── activity/ │ │ │ │ ├── BaseActivity.kt │ │ │ │ ├── BaseMVVMActivity.kt │ │ │ │ ├── BaseViewModePluginActivity.kt │ │ │ │ ├── BaseViewModelActivity.kt │ │ │ │ ├── BaseViewModelClassActivity.kt │ │ │ │ ├── BaseViewPluginResActivity.kt │ │ │ │ ├── WActivityManager.kt │ │ │ │ └── compose/ │ │ │ │ └── BaseComposeActivity.kt │ │ │ ├── adapter/ │ │ │ │ ├── BasePagerAdapter.kt │ │ │ │ ├── BasePluginRecyclerAdapter.kt │ │ │ │ ├── BaseRecyclerAdapter.kt │ │ │ │ └── ViewPage2ChildFragmentAdapter.kt │ │ │ ├── data/ │ │ │ │ └── DialogBean.kt │ │ │ ├── ex/ │ │ │ │ ├── Context.kt │ │ │ │ ├── Fragment.kt │ │ │ │ ├── FragmentActivity.kt │ │ │ │ ├── ImageView.kt │ │ │ │ ├── SwipeRefreshLayout.kt │ │ │ │ └── ViewModel.kt │ │ │ ├── fragment/ │ │ │ │ ├── BaseFragment.kt │ │ │ │ ├── BasePluginResFragment.kt │ │ │ │ ├── BaseViewModelClassFragment.kt │ │ │ │ ├── BaseViewModelFragment.kt │ │ │ │ └── BaseViewModelPluginFragment.kt │ │ │ ├── http/ │ │ │ │ ├── HttpRequest.kt │ │ │ │ └── HttpUrlConnectionRequest.kt │ │ │ ├── material/ │ │ │ │ └── ThemeUtils.kt │ │ │ ├── units/ │ │ │ │ ├── DeviceIdUtilX.kt │ │ │ │ ├── ImageUtils.kt │ │ │ │ ├── ResourceUtils.kt │ │ │ │ ├── ScreenManager.kt │ │ │ │ ├── SdkIntUtils.kt │ │ │ │ ├── ServiceUtil.kt │ │ │ │ ├── StatusBarUtil.kt │ │ │ │ └── WLog.kt │ │ │ ├── viewmodel/ │ │ │ │ └── BaseViewModel.kt │ │ │ └── widget/ │ │ │ ├── ButtomNavigationViewEx.kt │ │ │ ├── DividerGridItemDecoration.kt │ │ │ ├── DrawerBack.kt │ │ │ ├── MusicVisualizerView.kt │ │ │ └── OnRecyclerViewItemClickListener.kt │ │ ├── Wgllss-Dynamic-Plugin-Generate/ │ │ │ ├── wgllss-sample-create-all-app/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── version/ │ │ │ │ └── json/ │ │ │ │ └── Test.kt │ │ │ ├── wgllss-sample-create-version-config-annotations/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── annotations/ │ │ │ │ └── CreateVersionConfig.kt │ │ │ ├── wgllss-sample-create-version-config-app/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── version/ │ │ │ │ └── json/ │ │ │ │ └── Test.kt │ │ │ └── wgllss-sample-create-version-config-compiler/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── libs/ │ │ │ │ ├── Wgllss-Dynamic-Host-Protobuf-lib.jar │ │ │ │ └── classes.jar │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── compiler/ │ │ │ └── AptCreateConfigProcessor.kt │ │ ├── Wgllss-Dynamic-Plugin-Manager/ │ │ │ ├── Wgllss-Dynamic-Plugin-DownloadFace-Impl/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── plugin/ │ │ │ │ └── download_face/ │ │ │ │ └── DownLoadFaceImpl.kt │ │ │ ├── Wgllss-Dynamic-Plugin-Loader-Impl/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── plugin/ │ │ │ │ └── loader/ │ │ │ │ └── LoaderManagerImpl.kt │ │ │ └── Wgllss-Dynamic-Plugin-Manager/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── plugin/ │ │ │ └── manager/ │ │ │ ├── PluginManager.kt │ │ │ └── PluginResource.kt │ │ ├── Wgllss-Dynamic-Plugin-SDK/ │ │ │ ├── Wgllss-Dynamic-Plugin-Library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── consumer-rules.pro │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ ├── main/ │ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ │ └── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── dynamic/ │ │ │ │ │ └── runtime/ │ │ │ │ │ └── library/ │ │ │ │ │ ├── WXDynamicAidlInterface.java │ │ │ │ │ ├── WXHostActivityDelegate.java │ │ │ │ │ └── WXHostServiceDelegate.java │ │ │ │ └── test/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── plugin/ │ │ │ │ └── library/ │ │ │ │ └── ExampleUnitTest.kt │ │ │ └── Wgllss-Dynamic-Plugin-RunTime-Apk/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── consumer-rules.pro │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── plugin/ │ │ │ │ └── runtime/ │ │ │ │ ├── HostComposePluginActivity.java │ │ │ │ ├── HostPluginActivity.java │ │ │ │ ├── HostPluginService.java │ │ │ │ ├── PluginClassLoader.java │ │ │ │ ├── PluginProcessStartNotStickyService.java │ │ │ │ ├── PluginProcessStartRedeliverIntentService.java │ │ │ │ ├── PluginProcessStartStickyCompatibilityService.java │ │ │ │ ├── PluginProcessStartStickyService.java │ │ │ │ ├── PluginSingleInstanceActivity.java │ │ │ │ ├── PluginSingleInstanceComposeActivity.java │ │ │ │ ├── PluginSingleTaskActivity.java │ │ │ │ ├── PluginSingleTaskComposeActivity.java │ │ │ │ ├── PluginSingleTopActivity.java │ │ │ │ ├── PluginSingleTopComposeActivity.java │ │ │ │ ├── PluginStandardActivity.java │ │ │ │ ├── PluginStandardComposeActivity.java │ │ │ │ ├── PluginStartNotStickyService.java │ │ │ │ ├── PluginStartRedeliverIntentService.java │ │ │ │ ├── PluginStartStickyCompatibilityService.java │ │ │ │ └── PluginStartStickyService.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── runtime/ │ │ │ └── ExampleUnitTest.kt │ │ ├── Wgllss-Dynamic-Plugin-Sample/ │ │ │ ├── wgllss-sample-assets-source-apk/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── assets/ │ │ │ │ ├── css/ │ │ │ │ │ └── main.8f39d45c.css │ │ │ │ └── js/ │ │ │ │ ├── jquery.js │ │ │ │ └── jquery.lazyload.js │ │ │ ├── wgllss-sample-business-library/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── sample/ │ │ │ │ ├── data/ │ │ │ │ │ ├── ImgExtraData.kt │ │ │ │ │ ├── NewsBean.kt │ │ │ │ │ └── SampleItemBean.kt │ │ │ │ ├── datasource/ │ │ │ │ │ ├── net/ │ │ │ │ │ │ ├── HeaderInterceptor.kt │ │ │ │ │ │ ├── MyApi.kt │ │ │ │ │ │ └── RetrofitUtils.kt │ │ │ │ │ └── repository/ │ │ │ │ │ └── NewsRepository.kt │ │ │ │ ├── feature_system/ │ │ │ │ │ ├── music/ │ │ │ │ │ │ ├── exoplayerimpl/ │ │ │ │ │ │ │ ├── ExoPlayerUtils.kt │ │ │ │ │ │ │ └── MusicServiceConnection.kt │ │ │ │ │ │ ├── extensions/ │ │ │ │ │ │ │ ├── MediaExtensions.kt │ │ │ │ │ │ │ ├── MediaMetadataCompatExt.kt │ │ │ │ │ │ │ └── PlaybackStateCompatExt.kt │ │ │ │ │ │ └── notification/ │ │ │ │ │ │ ├── WXNotificationListener.kt │ │ │ │ │ │ └── WXPlayerNotificationManager.kt │ │ │ │ │ ├── room/ │ │ │ │ │ │ ├── CollectDataBase.kt │ │ │ │ │ │ ├── dao/ │ │ │ │ │ │ │ └── CollectDao.kt │ │ │ │ │ │ ├── help/ │ │ │ │ │ │ │ ├── RoomDBHelper.kt │ │ │ │ │ │ │ └── RoomDBMigration.kt │ │ │ │ │ │ └── table/ │ │ │ │ │ │ └── CollectTableBean.kt │ │ │ │ │ ├── savestatus/ │ │ │ │ │ │ └── MMKVHelp.kt │ │ │ │ │ ├── services/ │ │ │ │ │ │ └── MusicService.kt │ │ │ │ │ └── untils/ │ │ │ │ │ └── UUIDHelp.kt │ │ │ │ └── features_ui/ │ │ │ │ └── playing/ │ │ │ │ └── activity/ │ │ │ │ └── NotificationTargetActivity.kt │ │ │ ├── wgllss-sample-loader-version/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── loader/ │ │ │ │ └── version/ │ │ │ │ └── LoaderVersionImpl.kt │ │ │ ├── wgllss-sample-skin-resource-apk/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ │ ├── circle_gray_border.xml │ │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ │ ├── play_load_drawable.xml │ │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ │ └── switch_track_selector.xml │ │ │ │ ├── values/ │ │ │ │ │ ├── colors.xml │ │ │ │ │ ├── dimens.xml │ │ │ │ │ ├── ids.xml │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── themes.xml │ │ │ │ ├── values-night/ │ │ │ │ │ ├── colors.xml │ │ │ │ │ └── themes.xml │ │ │ │ ├── values-v27/ │ │ │ │ │ └── themes.xml │ │ │ │ └── values-v29/ │ │ │ │ └── themes.xml │ │ │ ├── wgllss-sample-ui-home/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ ├── impl/ │ │ │ │ │ └── ILoadHomeImpl.kt │ │ │ │ ├── initializer/ │ │ │ │ │ └── InitHomeFirstInitialize.kt │ │ │ │ ├── provider/ │ │ │ │ │ └── TestContentProvider.kt │ │ │ │ ├── sample/ │ │ │ │ │ ├── feature_home/ │ │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ │ └── HomeNewsAdapter.kt │ │ │ │ │ │ ├── fragment/ │ │ │ │ │ │ │ ├── HomeFragment.kt │ │ │ │ │ │ │ └── HomeTabFragment.kt │ │ │ │ │ │ ├── pkg/ │ │ │ │ │ │ │ └── ResourceContains.kt │ │ │ │ │ │ └── viewmodels/ │ │ │ │ │ │ ├── HomeTabViewModel.kt │ │ │ │ │ │ ├── HomeViewModel.kt │ │ │ │ │ │ └── SettingViewModel.kt │ │ │ │ │ └── feature_startup/ │ │ │ │ │ └── startup/ │ │ │ │ │ ├── GenerateHomeLayout.kt │ │ │ │ │ ├── HomeContains.kt │ │ │ │ │ ├── InitHomeFirstInitializeHelp.kt │ │ │ │ │ └── LaunchInflateKey.kt │ │ │ │ └── ui/ │ │ │ │ └── HomeActivity.kt │ │ │ ├── wgllss-sample-ui-loading/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ ├── initializer/ │ │ │ │ │ └── InitHomeFirstInitialize.kt │ │ │ │ ├── system/ │ │ │ │ │ └── broadcast/ │ │ │ │ │ ├── BroadCastAction.kt │ │ │ │ │ └── DownLoadCompleteBroadCast.kt │ │ │ │ └── ui/ │ │ │ │ └── HomeActivity.kt │ │ │ ├── wgllss-sample-ui-other/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── res/ │ │ │ │ └── layout/ │ │ │ │ ├── adapter_collection_item.xml │ │ │ │ ├── adapter_sample_item.xml │ │ │ │ ├── fragment_collection.xml │ │ │ │ ├── fragment_sample.xml │ │ │ │ └── fragment_setting.xml │ │ │ ├── wgllss-sample-ui-other-lib/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── wgllss/ │ │ │ │ │ └── sample/ │ │ │ │ │ ├── datasource/ │ │ │ │ │ │ ├── SettingRepository.kt │ │ │ │ │ │ └── SkinPluginBean.kt │ │ │ │ │ └── features_ui/ │ │ │ │ │ └── page/ │ │ │ │ │ ├── base/ │ │ │ │ │ │ ├── BasePluginActivity.kt │ │ │ │ │ │ ├── BasePluginFragment.kt │ │ │ │ │ │ └── SkinContains.kt │ │ │ │ │ └── home/ │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ ├── CollectionAdapter.kt │ │ │ │ │ │ ├── SampleAdapter.kt │ │ │ │ │ │ └── SkinAdapter.kt │ │ │ │ │ ├── fragment/ │ │ │ │ │ │ ├── CollectFragment.kt │ │ │ │ │ │ ├── SampleFragment.kt │ │ │ │ │ │ └── SettingFragment.kt │ │ │ │ │ └── viewmodels/ │ │ │ │ │ ├── CollectViewModel.kt │ │ │ │ │ ├── SampleViewModel.kt │ │ │ │ │ └── SettingViewModel.kt │ │ │ │ └── res/ │ │ │ │ └── layout/ │ │ │ │ ├── activity_locker.xml │ │ │ │ ├── activity_play.xml │ │ │ │ ├── adapter_home_item_music.xml │ │ │ │ ├── adapter_item_music.xml │ │ │ │ ├── adapter_music_playlist_item.xml │ │ │ │ ├── fragment_history.xml │ │ │ │ ├── fragment_locker.xml │ │ │ │ ├── fragment_play.xml │ │ │ │ ├── fragment_search.xml │ │ │ │ ├── fragment_setting.xml │ │ │ │ └── music_cd_layout.xml │ │ │ ├── wgllss-sample-ui-other2/ │ │ │ │ ├── .gitignore │ │ │ │ ├── build.gradle │ │ │ │ ├── proguard-rules.pro │ │ │ │ └── src/ │ │ │ │ └── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── res/ │ │ │ │ └── layout/ │ │ │ │ ├── activity_locker.xml │ │ │ │ ├── activity_other2.xml │ │ │ │ ├── activity_other3.xml │ │ │ │ ├── activity_play.xml │ │ │ │ ├── activity_video.xml │ │ │ │ ├── activity_webview.xml │ │ │ │ ├── dialog_sample.xml │ │ │ │ ├── fragment_activity_sample.xml │ │ │ │ ├── fragment_broadcast_sample.xml │ │ │ │ ├── fragment_dialog_sample.xml │ │ │ │ ├── fragment_locker.xml │ │ │ │ ├── fragment_notification_sample.xml │ │ │ │ ├── fragment_play.xml │ │ │ │ ├── fragment_provider_sample.xml │ │ │ │ ├── fragment_service_sample.xml │ │ │ │ ├── fragment_so_sample.xml │ │ │ │ └── music_cd_layout.xml │ │ │ └── wgllss-sample-ui-other2-lib2/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ ├── nativex/ │ │ │ │ ├── MainActivity.kt │ │ │ │ └── NativeCallBack.kt │ │ │ ├── sample/ │ │ │ │ └── features_ui/ │ │ │ │ └── page/ │ │ │ │ ├── base/ │ │ │ │ │ ├── BasePluginActivity.kt │ │ │ │ │ ├── BasePluginComposeActivity.kt │ │ │ │ │ ├── BasePluginFragment.kt │ │ │ │ │ └── SkinContains.kt │ │ │ │ └── other2/ │ │ │ │ ├── activity/ │ │ │ │ │ ├── AudioActivity.kt │ │ │ │ │ ├── ComposeDemoActivity.kt │ │ │ │ │ ├── Other2Activity.kt │ │ │ │ │ ├── Other3Activity.kt │ │ │ │ │ ├── VideoActivity.kt │ │ │ │ │ └── WebViewActivity.kt │ │ │ │ ├── broadcast/ │ │ │ │ │ └── TestBroadCast.kt │ │ │ │ ├── dialog/ │ │ │ │ │ └── MyDialog.kt │ │ │ │ ├── fragment/ │ │ │ │ │ ├── SampleActivityFragment.kt │ │ │ │ │ ├── SampleBroadCastFragment.kt │ │ │ │ │ ├── SampleContentProviderFragment.kt │ │ │ │ │ ├── SampleDialogFragment.kt │ │ │ │ │ ├── SampleMusicFragment.kt │ │ │ │ │ ├── SampleNotificationFragment.kt │ │ │ │ │ ├── SampleServiceFragment.kt │ │ │ │ │ └── SampleSoFragment.kt │ │ │ │ ├── service/ │ │ │ │ │ ├── MyProcessService.kt │ │ │ │ │ ├── MyService.kt │ │ │ │ │ ├── MyService2.kt │ │ │ │ │ └── MyService3.kt │ │ │ │ ├── viewmodel/ │ │ │ │ │ ├── ComposeDemoViewModel.kt │ │ │ │ │ ├── Other2ViewModel.kt │ │ │ │ │ ├── PlayModel.kt │ │ │ │ │ ├── SampleActivityViewModel.kt │ │ │ │ │ └── WebViewModel.kt │ │ │ │ └── web/ │ │ │ │ └── ImplWebViewClient.kt │ │ │ └── theme/ │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ │ └── Wgllss-Dynamic-Plugin_Skin/ │ │ ├── blue-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── brown-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── dark-blue-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── dark-green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── dark-red-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── light-green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── orange-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── pink-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ └── red-resource/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ ├── circle_gray_border.xml │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ ├── ic_baseline_grade_24.xml │ │ │ ├── ic_baseline_pause_36.xml │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ ├── ic_baseline_search_24.xml │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ ├── ic_home_black_24dp.xml │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ ├── ic_round_queue_music_24.xml │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ ├── play_load_drawable.xml │ │ │ ├── play_mode_level_list.xml │ │ │ ├── seek_bar_progress_style.xml │ │ │ ├── seekbar_circle_red_border.xml │ │ │ ├── seekbar_thumb.xml │ │ │ ├── switch_thumb_selector.xml │ │ │ └── switch_track_selector.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── ids.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ ├── values-night/ │ │ │ ├── colors.xml │ │ │ └── themes.xml │ │ ├── values-v27/ │ │ │ └── themes.xml │ │ └── values-v29/ │ │ └── themes.xml │ ├── WX-Dynamic-Host-SDK-Lib/ │ │ ├── Wgllss-Dynamic-Host-Lib/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── host/ │ │ │ │ └── wxdynamicpluginsdk/ │ │ │ │ └── ExampleInstrumentedTest.kt │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── host/ │ │ │ │ └── lib/ │ │ │ │ ├── classloader/ │ │ │ │ │ ├── PluginKey.java │ │ │ │ │ └── WXClassLoader.java │ │ │ │ ├── download/ │ │ │ │ │ ├── DownLoadResult.kt │ │ │ │ │ ├── DynamicDownloadPlugin.kt │ │ │ │ │ └── IDynamicDownLoadFace.kt │ │ │ │ ├── home/ │ │ │ │ │ └── ILoadHome.kt │ │ │ │ ├── impl/ │ │ │ │ │ ├── WXDynamicLoader.kt │ │ │ │ │ └── WXLoaderManagerImpl.kt │ │ │ │ ├── loader/ │ │ │ │ │ └── ILoaderManager.kt │ │ │ │ ├── loader_base/ │ │ │ │ │ ├── BaseLoaderManagerImpl.kt │ │ │ │ │ └── DynamicManageUtils.kt │ │ │ │ ├── provider/ │ │ │ │ │ ├── ProviderAuthority.kt │ │ │ │ │ ├── WXHostContentProviderDelegate.kt │ │ │ │ │ ├── WXPluginContentProvider.kt │ │ │ │ │ └── WXProviderManager.kt │ │ │ │ └── runtime/ │ │ │ │ ├── ContainerClassLoader.kt │ │ │ │ └── MultiDynamicRuntime.kt │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── host/ │ │ │ └── wxdynamicpluginsdk/ │ │ │ └── ExampleUnitTest.kt │ │ └── Wgllss-Dynamic-Host-Version-Lib/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ └── dynamic/ │ │ └── host/ │ │ └── lib/ │ │ ├── constant/ │ │ │ └── DynamicPluginConstant.kt │ │ └── version/ │ │ └── ILoaderVersion.kt │ └── WX-Maven/ │ ├── WX-Host/ │ │ ├── sample/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ ├── sign/ │ │ │ │ └── WXSample.jks │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets/ │ │ │ │ └── loading_1000 │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── host/ │ │ │ │ ├── FaceImpl.kt │ │ │ │ ├── SampleApplication.kt │ │ │ │ └── VersionImpl.kt │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-v24/ │ │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ └── ic_launcher.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ └── themes.xml │ │ │ └── xml/ │ │ │ ├── backup_rules.xml │ │ │ ├── data_extraction_rules.xml │ │ │ └── network_security_config.xml │ │ └── sample-lib/ │ │ ├── maven-wgllss-business-re-library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── sample/ │ │ │ │ └── feature_system/ │ │ │ │ └── globle/ │ │ │ │ └── Constants.kt │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── sample/ │ │ │ └── ExampleUnitTest.kt │ │ ├── maven-wgllss-common-re-library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── libs/ │ │ │ │ └── com_wang_avi_library-2.1.3.aar │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── core/ │ │ │ │ ├── dialog/ │ │ │ │ │ └── CommonLoadingView.kt │ │ │ │ ├── ex/ │ │ │ │ │ ├── ContextEX.kt │ │ │ │ │ ├── Flow.kt │ │ │ │ │ └── NetWorkHelp.kt │ │ │ │ ├── permissions/ │ │ │ │ │ ├── PermissionInterceptor.kt │ │ │ │ │ └── PermissionNameConvert.kt │ │ │ │ ├── units/ │ │ │ │ │ ├── AppGlobals.kt │ │ │ │ │ ├── DeviceIdUtil.kt │ │ │ │ │ └── LogTimer.kt │ │ │ │ └── widget/ │ │ │ │ └── CommonToast.kt │ │ │ └── res/ │ │ │ ├── anim/ │ │ │ │ └── anim_alpha_121.xml │ │ │ ├── drawable/ │ │ │ │ ├── button_bg_transparent_helf.xml │ │ │ │ └── progressbar_shape.xml │ │ │ ├── layout/ │ │ │ │ └── common_loading.xml │ │ │ └── values/ │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ ├── maven-wgllss-dynamic-host-library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── consumer-rules.pro │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── host/ │ │ │ │ └── library/ │ │ │ │ └── ExampleInstrumentedTest.kt │ │ │ ├── main/ │ │ │ │ └── AndroidManifest.xml │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── host/ │ │ │ └── library/ │ │ │ └── ExampleUnitTest.kt │ │ └── maven-wgllss-dynamic-host-skin-resource-lib/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ ├── splash_preview.xml │ │ │ └── splash_preview_dark.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── ids.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ ├── values-night/ │ │ │ ├── colors.xml │ │ │ └── themes.xml │ │ ├── values-v27/ │ │ │ └── themes.xml │ │ └── values-v29/ │ │ └── themes.xml │ └── WX-Plugin/ │ ├── Maven-Wgllss-Dynamic-Plugin-Common-Library/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ └── core/ │ │ ├── activity/ │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseMVVMActivity.kt │ │ │ ├── BaseViewModePluginActivity.kt │ │ │ ├── BaseViewModelActivity.kt │ │ │ ├── BaseViewModelClassActivity.kt │ │ │ ├── BaseViewPluginResActivity.kt │ │ │ ├── WActivityManager.kt │ │ │ └── compose/ │ │ │ └── BaseComposeActivity.kt │ │ ├── adapter/ │ │ │ ├── BasePagerAdapter.kt │ │ │ ├── BasePluginRecyclerAdapter.kt │ │ │ ├── BaseRecyclerAdapter.kt │ │ │ └── ViewPage2ChildFragmentAdapter.kt │ │ ├── data/ │ │ │ └── DialogBean.kt │ │ ├── ex/ │ │ │ ├── Context.kt │ │ │ ├── Fragment.kt │ │ │ ├── FragmentActivity.kt │ │ │ ├── ImageView.kt │ │ │ ├── SwipeRefreshLayout.kt │ │ │ └── ViewModel.kt │ │ ├── fragment/ │ │ │ ├── BaseFragment.kt │ │ │ ├── BasePluginResFragment.kt │ │ │ ├── BaseViewModelClassFragment.kt │ │ │ ├── BaseViewModelFragment.kt │ │ │ └── BaseViewModelPluginFragment.kt │ │ ├── http/ │ │ │ ├── HttpRequest.kt │ │ │ └── HttpUrlConnectionRequest.kt │ │ ├── material/ │ │ │ └── ThemeUtils.kt │ │ ├── units/ │ │ │ ├── DeviceIdUtilX.kt │ │ │ ├── ImageUtils.kt │ │ │ ├── ResourceUtils.kt │ │ │ ├── ScreenManager.kt │ │ │ ├── SdkIntUtils.kt │ │ │ ├── ServiceUtil.kt │ │ │ ├── StatusBarUtil.kt │ │ │ └── WLog.kt │ │ ├── viewmodel/ │ │ │ └── BaseViewModel.kt │ │ └── widget/ │ │ ├── ButtomNavigationViewEx.kt │ │ ├── DividerGridItemDecoration.kt │ │ ├── DrawerBack.kt │ │ ├── MusicVisualizerView.kt │ │ └── OnRecyclerViewItemClickListener.kt │ ├── Maven-Wgllss-Dynamic-Plugin-Generate/ │ │ ├── maven-wgllss-sample-create-all-app/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── version/ │ │ │ └── json/ │ │ │ └── Test.kt │ │ ├── maven-wgllss-sample-create-version-config-annotations/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── annotations/ │ │ │ └── CreateVersionConfig.kt │ │ ├── maven-wgllss-sample-create-version-config-app/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── version/ │ │ │ └── json/ │ │ │ └── Test.kt │ │ └── maven-wgllss-sample-create-version-config-compiler/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── libs/ │ │ │ ├── Wgllss-Dynamic-Host-Protobuf-lib.jar │ │ │ └── classes.jar │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ └── compiler/ │ │ └── AptCreateConfigProcessor.kt │ ├── Maven-Wgllss-Dynamic-Plugin-Manager/ │ │ ├── Maven-Wgllss-Dynamic-Plugin-DownloadFace-Impl/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── plugin/ │ │ │ └── download_face/ │ │ │ └── DownLoadFaceImpl.kt │ │ ├── Maven-Wgllss-Dynamic-Plugin-Loader-Impl/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── plugin/ │ │ │ └── loader/ │ │ │ └── LoaderManagerImpl.kt │ │ └── Maven-Wgllss-Dynamic-Plugin-Manager/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ └── dynamic/ │ │ └── plugin/ │ │ └── manager/ │ │ ├── PluginManager.kt │ │ └── PluginResource.kt │ ├── Maven-Wgllss-Dynamic-Plugin-SDK/ │ │ ├── Maven-Wgllss-Dynamic-Plugin-Library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── consumer-rules.pro │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── dynamic/ │ │ │ │ └── runtime/ │ │ │ │ └── library/ │ │ │ │ ├── WXDynamicAidlInterface.java │ │ │ │ ├── WXHostActivityDelegate.java │ │ │ │ └── WXHostServiceDelegate.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── plugin/ │ │ │ └── library/ │ │ │ └── ExampleUnitTest.kt │ │ └── Maven-Wgllss-Dynamic-Plugin-RunTime-Apk/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── consumer-rules.pro │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ └── plugin/ │ │ │ └── runtime/ │ │ │ ├── HostComposePluginActivity.java │ │ │ ├── HostPluginActivity.java │ │ │ ├── HostPluginService.java │ │ │ ├── PluginClassLoader.java │ │ │ ├── PluginProcessStartNotStickyService.java │ │ │ ├── PluginProcessStartRedeliverIntentService.java │ │ │ ├── PluginProcessStartStickyCompatibilityService.java │ │ │ ├── PluginProcessStartStickyService.java │ │ │ ├── PluginSingleInstanceActivity.java │ │ │ ├── PluginSingleInstanceComposeActivity.java │ │ │ ├── PluginSingleTaskActivity.java │ │ │ ├── PluginSingleTaskComposeActivity.java │ │ │ ├── PluginSingleTopActivity.java │ │ │ ├── PluginSingleTopComposeActivity.java │ │ │ ├── PluginStandardActivity.java │ │ │ ├── PluginStandardComposeActivity.java │ │ │ ├── PluginStartNotStickyService.java │ │ │ ├── PluginStartRedeliverIntentService.java │ │ │ ├── PluginStartStickyCompatibilityService.java │ │ │ └── PluginStartStickyService.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ └── dynamic/ │ │ └── runtime/ │ │ └── ExampleUnitTest.kt │ ├── Maven-Wgllss-Dynamic-Plugin-Sample/ │ │ ├── README.md │ │ ├── maven-wgllss-sample-assets-source-apk/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── assets/ │ │ │ ├── css/ │ │ │ │ └── main.8f39d45c.css │ │ │ └── js/ │ │ │ ├── jquery.js │ │ │ └── jquery.lazyload.js │ │ ├── maven-wgllss-sample-business-library/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── sample/ │ │ │ ├── data/ │ │ │ │ ├── ImgExtraData.kt │ │ │ │ ├── NewsBean.kt │ │ │ │ └── SampleItemBean.kt │ │ │ ├── datasource/ │ │ │ │ ├── net/ │ │ │ │ │ ├── HeaderInterceptor.kt │ │ │ │ │ ├── MyApi.kt │ │ │ │ │ └── RetrofitUtils.kt │ │ │ │ └── repository/ │ │ │ │ └── NewsRepository.kt │ │ │ ├── feature_system/ │ │ │ │ ├── music/ │ │ │ │ │ ├── exoplayerimpl/ │ │ │ │ │ │ ├── ExoPlayerUtils.kt │ │ │ │ │ │ └── MusicServiceConnection.kt │ │ │ │ │ ├── extensions/ │ │ │ │ │ │ ├── MediaExtensions.kt │ │ │ │ │ │ ├── MediaMetadataCompatExt.kt │ │ │ │ │ │ └── PlaybackStateCompatExt.kt │ │ │ │ │ └── notification/ │ │ │ │ │ ├── WXNotificationListener.kt │ │ │ │ │ └── WXPlayerNotificationManager.kt │ │ │ │ ├── room/ │ │ │ │ │ ├── CollectDataBase.kt │ │ │ │ │ ├── dao/ │ │ │ │ │ │ └── CollectDao.kt │ │ │ │ │ ├── help/ │ │ │ │ │ │ ├── RoomDBHelper.kt │ │ │ │ │ │ └── RoomDBMigration.kt │ │ │ │ │ └── table/ │ │ │ │ │ └── CollectTableBean.kt │ │ │ │ ├── savestatus/ │ │ │ │ │ └── MMKVHelp.kt │ │ │ │ ├── services/ │ │ │ │ │ └── MusicService.kt │ │ │ │ └── untils/ │ │ │ │ └── UUIDHelp.kt │ │ │ └── features_ui/ │ │ │ └── playing/ │ │ │ └── activity/ │ │ │ └── NotificationTargetActivity.kt │ │ ├── maven-wgllss-sample-loader-version/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── loader/ │ │ │ └── version/ │ │ │ └── LoaderVersionImpl.kt │ │ ├── maven-wgllss-sample-skin-resource-apk/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-wgllss-sample-ui-home/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ ├── impl/ │ │ │ │ └── ILoadHomeImpl.kt │ │ │ ├── initializer/ │ │ │ │ └── InitHomeFirstInitialize.kt │ │ │ ├── provider/ │ │ │ │ └── TestContentProvider.kt │ │ │ ├── sample/ │ │ │ │ ├── feature_home/ │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ └── HomeNewsAdapter.kt │ │ │ │ │ ├── fragment/ │ │ │ │ │ │ ├── HomeFragment.kt │ │ │ │ │ │ └── HomeTabFragment.kt │ │ │ │ │ ├── pkg/ │ │ │ │ │ │ └── ResourceContains.kt │ │ │ │ │ └── viewmodels/ │ │ │ │ │ ├── HomeTabViewModel.kt │ │ │ │ │ ├── HomeViewModel.kt │ │ │ │ │ └── SettingViewModel.kt │ │ │ │ └── feature_startup/ │ │ │ │ └── startup/ │ │ │ │ ├── GenerateHomeLayout.kt │ │ │ │ ├── HomeContains.kt │ │ │ │ ├── InitHomeFirstInitializeHelp.kt │ │ │ │ └── LaunchInflateKey.kt │ │ │ └── ui/ │ │ │ └── HomeActivity.kt │ │ ├── maven-wgllss-sample-ui-loading/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── wgllss/ │ │ │ └── dynamic/ │ │ │ ├── initializer/ │ │ │ │ └── InitHomeFirstInitialize.kt │ │ │ ├── system/ │ │ │ │ └── broadcast/ │ │ │ │ ├── BroadCastAction.kt │ │ │ │ └── DownLoadCompleteBroadCast.kt │ │ │ └── ui/ │ │ │ └── HomeActivity.kt │ │ ├── maven-wgllss-sample-ui-other/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ └── layout/ │ │ │ ├── adapter_collection_item.xml │ │ │ ├── adapter_sample_item.xml │ │ │ ├── fragment_collection.xml │ │ │ ├── fragment_sample.xml │ │ │ └── fragment_setting.xml │ │ ├── maven-wgllss-sample-ui-other-lib/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── wgllss/ │ │ │ │ └── sample/ │ │ │ │ ├── datasource/ │ │ │ │ │ ├── SettingRepository.kt │ │ │ │ │ └── SkinPluginBean.kt │ │ │ │ └── features_ui/ │ │ │ │ └── page/ │ │ │ │ ├── base/ │ │ │ │ │ ├── BasePluginActivity.kt │ │ │ │ │ ├── BasePluginFragment.kt │ │ │ │ │ └── SkinContains.kt │ │ │ │ └── home/ │ │ │ │ ├── adapter/ │ │ │ │ │ ├── CollectionAdapter.kt │ │ │ │ │ ├── SampleAdapter.kt │ │ │ │ │ └── SkinAdapter.kt │ │ │ │ ├── fragment/ │ │ │ │ │ ├── CollectFragment.kt │ │ │ │ │ ├── SampleFragment.kt │ │ │ │ │ └── SettingFragment.kt │ │ │ │ └── viewmodels/ │ │ │ │ ├── CollectViewModel.kt │ │ │ │ ├── SampleViewModel.kt │ │ │ │ └── SettingViewModel.kt │ │ │ └── res/ │ │ │ └── layout/ │ │ │ ├── activity_locker.xml │ │ │ ├── activity_play.xml │ │ │ ├── adapter_home_item_music.xml │ │ │ ├── adapter_item_music.xml │ │ │ ├── adapter_music_playlist_item.xml │ │ │ ├── fragment_history.xml │ │ │ ├── fragment_locker.xml │ │ │ ├── fragment_play.xml │ │ │ ├── fragment_search.xml │ │ │ ├── fragment_setting.xml │ │ │ └── music_cd_layout.xml │ │ ├── maven-wgllss-sample-ui-other2/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ └── layout/ │ │ │ ├── activity_locker.xml │ │ │ ├── activity_other2.xml │ │ │ ├── activity_other3.xml │ │ │ ├── activity_play.xml │ │ │ ├── activity_video.xml │ │ │ ├── activity_webview.xml │ │ │ ├── dialog_sample.xml │ │ │ ├── fragment_activity_sample.xml │ │ │ ├── fragment_broadcast_sample.xml │ │ │ ├── fragment_dialog_sample.xml │ │ │ ├── fragment_locker.xml │ │ │ ├── fragment_notification_sample.xml │ │ │ ├── fragment_play.xml │ │ │ ├── fragment_provider_sample.xml │ │ │ ├── fragment_service_sample.xml │ │ │ ├── fragment_so_sample.xml │ │ │ └── music_cd_layout.xml │ │ └── maven-wgllss-sample-ui-other2-lib2/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── wgllss/ │ │ ├── nativex/ │ │ │ ├── MainActivity.kt │ │ │ └── NativeCallBack.kt │ │ ├── sample/ │ │ │ └── features_ui/ │ │ │ └── page/ │ │ │ ├── base/ │ │ │ │ ├── BasePluginActivity.kt │ │ │ │ ├── BasePluginComposeActivity.kt │ │ │ │ ├── BasePluginFragment.kt │ │ │ │ └── SkinContains.kt │ │ │ └── other2/ │ │ │ ├── activity/ │ │ │ │ ├── AudioActivity.kt │ │ │ │ ├── ComposeDemoActivity.kt │ │ │ │ ├── Other2Activity.kt │ │ │ │ ├── Other3Activity.kt │ │ │ │ ├── VideoActivity.kt │ │ │ │ └── WebViewActivity.kt │ │ │ ├── broadcast/ │ │ │ │ └── TestBroadCast.kt │ │ │ ├── dialog/ │ │ │ │ └── MyDialog.kt │ │ │ ├── fragment/ │ │ │ │ ├── SampleActivityFragment.kt │ │ │ │ ├── SampleBroadCastFragment.kt │ │ │ │ ├── SampleContentProviderFragment.kt │ │ │ │ ├── SampleDialogFragment.kt │ │ │ │ ├── SampleMusicFragment.kt │ │ │ │ ├── SampleNotificationFragment.kt │ │ │ │ ├── SampleServiceFragment.kt │ │ │ │ └── SampleSoFragment.kt │ │ │ ├── service/ │ │ │ │ ├── MyProcessService.kt │ │ │ │ ├── MyService.kt │ │ │ │ ├── MyService2.kt │ │ │ │ └── MyService3.kt │ │ │ ├── viewmodel/ │ │ │ │ ├── ComposeDemoViewModel.kt │ │ │ │ ├── Other2ViewModel.kt │ │ │ │ ├── PlayModel.kt │ │ │ │ ├── SampleActivityViewModel.kt │ │ │ │ └── WebViewModel.kt │ │ │ └── web/ │ │ │ └── ImplWebViewClient.kt │ │ └── theme/ │ │ ├── Color.kt │ │ ├── Theme.kt │ │ └── Type.kt │ ├── Maven-Wgllss-Dynamic-Plugin_Skin/ │ │ ├── maven-blue-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-brown-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-dark-blue-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-dark-green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-dark-red-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-light-green-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-orange-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ ├── maven-pink-resource/ │ │ │ ├── .gitignore │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ │ ├── circle_gray_border.xml │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ ├── ic_baseline_grade_24.xml │ │ │ │ ├── ic_baseline_pause_36.xml │ │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ │ ├── ic_baseline_search_24.xml │ │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ │ ├── ic_home_black_24dp.xml │ │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ │ ├── ic_round_queue_music_24.xml │ │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ │ ├── play_load_drawable.xml │ │ │ │ ├── play_mode_level_list.xml │ │ │ │ ├── seek_bar_progress_style.xml │ │ │ │ ├── seekbar_circle_red_border.xml │ │ │ │ ├── seekbar_thumb.xml │ │ │ │ ├── switch_thumb_selector.xml │ │ │ │ └── switch_track_selector.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── ids.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ ├── values-night/ │ │ │ │ ├── colors.xml │ │ │ │ └── themes.xml │ │ │ ├── values-v27/ │ │ │ │ └── themes.xml │ │ │ └── values-v29/ │ │ │ └── themes.xml │ │ └── maven-red-resource/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── bottom_navigation_color_selector.xml │ │ │ ├── circle_gray_border.xml │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ ├── ic_baseline_grade_24.xml │ │ │ ├── ic_baseline_pause_36.xml │ │ │ ├── ic_baseline_play_arrow_36.xml │ │ │ ├── ic_baseline_search_24.xml │ │ │ ├── ic_baseline_skip_next_36.xml │ │ │ ├── ic_baseline_skip_previous_36.xml │ │ │ ├── ic_dashboard_black_24dp.xml │ │ │ ├── ic_home_black_24dp.xml │ │ │ ├── ic_notifications_black_24dp.xml │ │ │ ├── ic_round_queue_music_24.xml │ │ │ ├── play_btn_play_pause_selector.xml │ │ │ ├── play_load_drawable.xml │ │ │ ├── play_mode_level_list.xml │ │ │ ├── seek_bar_progress_style.xml │ │ │ ├── seekbar_circle_red_border.xml │ │ │ ├── seekbar_thumb.xml │ │ │ ├── switch_thumb_selector.xml │ │ │ └── switch_track_selector.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── ids.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ ├── values-night/ │ │ │ ├── colors.xml │ │ │ └── themes.xml │ │ ├── values-v27/ │ │ │ └── themes.xml │ │ └── values-v29/ │ │ └── themes.xml │ └── README.md ├── WX-Resource/ │ ├── B05F9543937A5BA61901FC14F2540C62DA3E86C2/ │ │ └── 10000/ │ │ ├── classes_business_lib_dex │ │ ├── classes_business_web_res │ │ ├── classes_common_lib_dex │ │ ├── classes_common_skin_res │ │ ├── classes_home_dex │ │ ├── classes_loading_dex │ │ ├── classes_manager_dex │ │ ├── classes_other2_dex │ │ ├── classes_other2_res │ │ ├── classes_other_dex │ │ ├── classes_other_res │ │ ├── classes_version_dex │ │ ├── classes_wgllss_dynamic_plugin_runtime │ │ └── vc │ ├── dxde_m_p/ │ │ └── 10000/ │ │ ├── classes_business_lib_dex │ │ ├── classes_business_web_res │ │ ├── classes_common_lib_dex │ │ ├── classes_common_skin_res │ │ ├── classes_home_dex │ │ ├── classes_loading_dex │ │ ├── classes_manager_dex │ │ ├── classes_other2_dex │ │ ├── classes_other2_res │ │ ├── classes_other_dex │ │ ├── classes_other_res │ │ ├── classes_version_dex │ │ ├── classes_wgllss_dynamic_plugin_runtime │ │ └── vc │ └── skins/ │ ├── blue.apk │ ├── brown.apk │ ├── dark_blue.apk │ ├── dark_red.apk │ ├── light_green.apk │ ├── orange.apk │ ├── pink.apk │ ├── red_green.apk │ ├── skin_dark_green.apk │ ├── skin_green.apk │ └── skins.txt ├── build.gradle ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/caches /.idea/libraries /.idea/modules.xml /.idea/workspace.xml /.idea/navEditor.xml /.idea /.idea/assetWizardSettings.xml .DS_Store /build /captures .externalNativeBuild .cxx local.properties ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, wgllss 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # WXDynamicPlugin ## 介绍 #### 最新接入研究配置参考文章介绍 [Compose的全动态插件化框架支持了,已更新到AGP 8.6,Kotlin2.0.20,支持Compose](https://juejin.cn/post/7435587382345482303) #### 插件化模块按需下载首页之外模块 [按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的](https://juejin.cn/post/7497428040484241462) #### **WXDynamicPlugin是由本人自住研发的Android插件框架** ### 零反射,零HooK,全动态化,插件化框架,全网唯一结合启动优化的插件化架构 ## 示例Sample (注意,请不要抓包,设置代理等!!!请不要抓包,设置代理等!!!) ![扫码下载](https://raw.githubusercontent.com/wgllss/WXDynamicPlugin/master/WX-Resource/wx-pic/Qrcode.png) ## 示例Sample截图 | | | | |-------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------| | | | | | | | | | | | | | | | | [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () [//]: # () ## 与市面上其他插件框架相比,WXDynamicPlugin主要具有以下优势和特点 ### 优势: #### 1.支持宿主就一个空壳子,并且启动速度不受任何影响,做到真正原生不用发版 #### 2.插件打包支持“分布式”,多模块单独插件,单独下载,单独加载,单独访问 #### 3.支持接入到宿主的那仅有的一小部分代码 都可以动态更新(插件下载逻辑,版本管理,下载服务器地址,环境全动态化) #### 4.支持Debug调试插件,不存在插件调试难度 ### 特点: * **零反射无Hack实现插件技术**:从理论上就已经确定无需对任何系统做兼容开发,更无任何隐藏API调用,和Google限制非公开SDK接口访问的策略完全不冲突。 * **全动态插件框架**:一次性实现完美的插件框架很难,但WXDynamicPlugin将这些全部动态化来实现,使插件化框架代码也成为了插件,同时,宿主下载插件的逻辑,版本控制也可以插件化起来,使得插件的迭代,及插件化框架的修改,以及可能涉及到宿主下载插件逻辑,版本控制逻辑,加载插件逻辑,这些全部动态化起来。目前市面上插件化框架,都没有实现插件下载到本地逻辑的动态化起来 * **插件极限瘦身优化**:编译出插件体积最小,所有插件模块总体积加载起来不到500k,单个模块70k左右,同时可以让各个功能模块单独插件化起来,市面上插件化框架插件体积编译出来基本都3M以上 * **宿主增量极小**:接入宿主的代码全Kotlin实现,真正插件化框架实现宿主接入代码仅4K多,加上下载逻辑,插件版本控制加载接入宿主代码仅60k左右,加上下载版本判断逻辑总共方法数仅80个方法数 * **极限启动优化性能**:做到宿主空壳子,第一次启动就下载到本地到加载,到显示到第一个页面,所需要的总耗时最小,基本是秒开,这得益于插件模块编译出来体积最小化,4G网络基本500ms就下载完了,如果插件编译出来基本3M以上,那么从服务端下载到本地至少10s以上,第一次再加载一个3M的插件又去了2~ 3s,第一次进入到主UI界面,差不多20s去了。而WXDynamicPlugin真正做到接入插件化后都比各大厂主流顶级App,没有通过宿主接插件化启动时间还快 ## 支持特性 * 四大组件 Activity ,Service , ContentProvider ,Broadcaster * 跨进程使用插件Service * fragment * assets * 插件访问宿主类 * 插件之间可以互不依赖,也可以存在有依赖关系 * 通知栏 * So加载 * 分段加载插件(多Apk分别加载或多Apk以此依赖加载) * 一个app 分多个模块单独加载 * 一个Activity中加载多个Apk中的View * 支持插件调试debug * 支持Compose * 等等…… ## 插件化框架对比 | 插件化框架 | Shadow | WXDynamicPlugin | |---------------|-------------|-----------------| | 插件打包体积 | 3M以上 | 500k左右 ✅ | | 极致化下载管理版本控制 | 需自己实现 | 1步到位 ✅ | | 插件加载逻辑 | 宿主->管理器->插件 | 宿主->插件 ✅ | | 首次插件下载到展示首页耗时 | 3~5s以上? | 1s内 ✅ | | 插件已经到本地后加载速度 | 1500ms以上? | 500ms内 ✅ | | 全动态化 | 部分支持 | 支持 ✅ | | 插件化框架动态化 | 支持 | 支持 ✅ | | 下载逻辑代码动态化 | 不支持 | 支持 ✅ | | 版本控制代码动态化 | 不支持 | 支持 ✅ | | 插件调试debug | 不支持 | 支持 ✅ | | Compose | 不支持 | 支持 ✅ | ## 示例运行: * **方式1:扫码安装即可** * **方式2:拉取代码,查看空壳子宿主工程,运行sample** * **以上两种运行实例方式宿主都是空壳子,所有插件存放在我配置的服务器地址** * **想把插件换成自己服务器上面,自己打包插件,想看插件具体写法,请放开 settings.gradle 中第150行 到 212行的注释 (为了拉取下来只运行宿主空壳子注释掉了),并按照下面文档进行相关配置** #### 最新接入研究配置参考文章介绍 [Compose的全动态插件化框架支持了,已更新到AGP 8.6,Kotlin2.0.20,支持Compose](https://juejin.cn/post/7435587382345482303) #### 插件化模块按需下载首页之外模块 [按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的](https://juejin.cn/post/7497428040484241462) ## 编译与开发环境 #### 环境准备 * **AS设置JDK 选17,电脑java版本需要安装 1.8.xxx(这是电脑安装的JDK,电脑!!!,不是AS), 打开工程下 local.properties** ##### 以下为我本地电脑配置,需要添加一行下面一句,并改成自己电脑配置: ``` workingDirPath=D\:\\android_software\\android_sdk\\android_sdk\\build-tools\\32.0.0\\ ``` * **如果电脑安装了几个版本的JDK,再次安装的JDK1.8.xxx后,因为有多个JDK共存,可拉取master-d8分支,单独配置JDK环境变量如下:** ##### 以下为我本地电脑配置,需要添加一行下面一句,并改成自己电脑配置: ``` jdkDirPath=C\:\\Program Files\\Java\\jdk1.8.0_181\\ ``` * **最新版本AS(Android Studio Ladybug 2024.2.1 Patch 3)以上提示JDK需要 17时:需要修改如下2个工程:** * **maven-wgllss-sample-create-version-config-compiler 和 maven-wgllss-sample-create-version-config-annotations工程都需要java版本需要改成如下17** ``` java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } ``` * **最新版本AS(Android Studio Meerkat Feature Drop | 2024.3.2)以上提示JDK需要 21时:需要修改上面配置2个工程改成21:** ##### 然后在IDE中选择 app 或 sample 模块直接运行,如下: ## 项目工程目录截图 ## 项目工程目录介绍 | 文件夹 | 介绍 | 接入方式 | |-------------------------|---------------------|--------------------| | WX-Code | 示例工程全源码级接入方式 | 接入方式一:依赖host模块工程 | | WX-Dynamic-Host-SDK-Lib | 宿主工程所依赖的lib工程源码 | | | WX-Maven | 示例工程maven依赖仓库方式接入工程 | 接入方式二:maven引入host包 | * **特别说明**:WX-Code 和 WX-Maven 下实际代码内容一样,目录结构一样,唯一区别接入全动态host代码方式不一样,另外WX-Maven 下所有文件夹和项目工程名多了 maven前缀,用于在同一工程下区分成 2个不同的项目 #### 推荐用方式二: Maven接入方式 #### 为了方便编译查看,已经注释掉 settings.gradle 中第35行到119行,需要看源码及源码方式接入(WX-Code下面),请自行放开注释 #### 以 WX-Maven下目录结构介绍为例: #### WX-Host: 下面全部为host宿主项目代码   sample: host宿主真实工程app #####   sample-lib: 下面为宿主工程依赖的4个工程模块     maven-wgllss-business-re-library:涉及到app的公共业务带res资源的模块lib     maven-wgllss-common-re-library:涉及到公共代码带res资源的模块lib     maven-wgllss-dynamic-host-library:宿主里manifest注册所必备的四大组件等lib     maven-wgllss-dynamic-host-skin-resource-lib:宿主所必须的资源样式主题等lib #### WX-Plugin: 该文件夹下面的所有工程都是插件的形式,不存在宿主里面   Maven-Wgllss-Dynamic-Plugin-Common-Library: 插件中公共代码   Maven-Wgllss-Dynamic-Plugin-Generate: 插件中打包所用的apt工程   Maven-Wgllss-Dynamic-Plugin-Manager: 插件中管理插件,管理动态代码的3个工程   Maven-Wgllss-Dynamic-Plugin-Sample: 插件中真正业务代码插件工程   Maven-Wgllss-Dynamic-Plugin-SDK: 插件框架四大组件SDK代码,以插件形式存在   Maven-Wgllss-Dynamic-Plugin_Skin: 插件中换皮肤资源 ### WX-Resource: 为项目已经打包好的插件,so,皮肤包文件等 存放的文件夹 #### 上面介绍 直接 run运行 ,打开app 进入宿主,直接下载的插件 为我已经放在准好的服务器上面了 #### maven接入方式 请不要设置代理抓包!!!   可以通过源码工程自行打包,上传到自己的服务器上部署,方法如下:   找到 WX/WX-Maven/WX-Host/sample/ com.wgllss.dynamic.host.FaceImpl ``` // override fun getHostL() = "http://192.168.3.21:8080/assets/WXDynamicPlugin/" // override fun getHostL() = "http://192.168.1.9:8080/assets/WXDynamicPlugin/" //todo 自己本地搭一个服务器,或者 自己服务器 或者 像我一样在gitee上面在自己的项目下建一个文件当作服务器 供下载, // 切记不要往往我的 gitee 项目上面推 override fun getHostL() = "https://gitee.com/wgllss888/WXDynamicPlugin/raw/master/WX-Resource/" /** 0:WXDynamicPlugin 动态化插件框架 理论上已经做到了可以完全不动宿主,但是如果一定要动宿主 可以提供以下思路: * 1:可以根据 宿主版本号得到 宿主版本支持的 的插件, * 2:当宿主必须 需要升级时,升级后原版本的插件不可用了,插件配置在新宿主版本文件夹下面,原宿主版本文件夹可可以先动态配置 在启动页 升级下载新的宿主 * @example 宿主版本 10000 版本支持的插件 放在服务端 WXDynamicPlugin/10000/ 文件夹下 20000版本的插件放在 WXDynamicPlugin/20000/下面 */ override fun getBaseL(): String { if (TextUtils.isEmpty(baseXL)) { baseXL = StringBuilder().append(getHostL()).append(DeviceIdUtil.getDeviceId()).append("/").append(BuildConfig.VERSION_CODE).append("/").toString() } return baseXL } ```   修改 getHostL() 地址为自己服务器地址, 修改 getBaseL() 中主要路劲,确保修改后地址可以访问通   然后将打包好的14个文件 放入getHostL()+getBaseL() 服务器文件夹下面   该 14个文件打包如下:   点击 assembleCreateAllFileRelease 等待 14个文件生成 ,一次不行,再次点击执行命令,如果还不生成,点击当前项目下maven-wgllss-sample-create-version-config-app的另一个assembleCreateVersion2FileRelease,生成2个文件之后再执行assembleCreateAllFileRelease   14个文件生成在以下目录:可以拷贝到自己的服务器上面供下载:即上面修改的 getHostL()+getBaseL() 服务器文件夹下面 ,同时把我准备的WX-Resource/so 文件夹和 WX-Resource/skins 文件夹拷贝过去,这是供sample 工程演示所用的,另外皮肤资源包多个apk文件也可以自行通过源码工程打包 ## 全动态插件化框架WXDynamicPlugin介绍文章: #### [(一) 插件化框架开发背景:零反射,零HooK,全动态化,插件化框架,全网唯一结合启动优化的插件化架构](https://juejin.cn/post/7347994218235363382) #### [(二)插件化框架主要介绍:零反射,零HooK,全动态化,插件化框架,全网唯一结合启动优化的插件化架构](https://juejin.cn/post/7367676494976532490) #### [(三)插件化框架内部详细介绍: 零反射,零HooK,全动态化,插件化框架,全网唯一结合启动优化的插件化架构](https://juejin.cn/post/7368397264026370083) #### [(四)插件化框架接入详细指南:零反射,零HooK,全动态化,插件化框架,全网唯一结合启动优化的插件化架构](https://juejin.cn/post/7372393698230550565) #### [(五) 大型项目架构:全动态插件化+模块化+Kotlin+协程+Flow+Retrofit+JetPack+MVVM+极限瘦身+极限启动优化+架构示例+全网唯一](https://juejin.cn/post/7381787510071934985) #### [(六) 大型项目架构:解析全动态插件化框架WXDynamicPlugin是如何做到全动态化的?](https://juejin.cn/post/7388891131037777929) #### [(七) 还在不断升级发版吗?从0到1带你看懂WXDynamicPlugin全动态插件化框架?](https://juejin.cn/post/7412124636239904819) #### [(八) Compose插件化:一个Demo带你入门Compose,同时带你入门插件化开发](https://juejin.cn/post/7425434773026537483) #### [(九) 花式高阶:插件化之Dex文件的高阶用法,极少人知道的秘密 ](https://juejin.cn/spost/7428216743166771212) #### [(十) 5种常见Android的SDK开发的方式,你知道几种? ](https://juejin.cn/post/7431088937278947391) #### [(十一) 5种WebView混合开发动态更新方式,直击痛点,有你想要的? ](https://juejin.cn/post/7433288965942165558) #### [(十二) Compose的全动态插件化框架支持了,已更新到AGP 8.6,Kotlin2.0.20,支持Compose](https://juejin.cn/post/7435587382345482303) #### [(十三)按需下载!!全动态插件化框架WXDynamicPlugin解析怎么支持的](https://juejin.cn/post/7497428040484241462) ## 作者开源 Compose可视化图表库 #### [(一)Compose曲线图表库WXChart,你只需要提供数据配置就行了](https://juejin.cn/post/7438835112790605865 "https://juejin.cn/post/7438835112790605865")\ #### [(二)Compose折线图,贝赛尔曲线图,柱状图,圆饼图,圆环图。带动画和点击效果](https://juejin.cn/post/7442228138501259283 "https://juejin.cn/post/7442228138501259283")\ #### [(三)全网最火视频,Compose代码写出来,动态可视化趋势视频,帅到爆](https://juejin.cn/post/7449238845214244875 "https://juejin.cn/post/7449238845214244875")\ #### [(四)全网最火可视化趋势视频实现深度解析,同时新增条形图表](https://juejin.cn/post/7449910229573943350) #### [(五)庆元旦,出排名,手撸全网火爆的排名视频,排名动态可视化](https://juejin.cn/post/7454386729702375465) #### [(六)Android六边形战士能力图绘制,Compose实现](https://juejin.cn/post/7457449985530757161) #### [(七)ndroid之中美PK,赛事PK对比图Compose实现](https://juejin.cn/post/7462544107527389247) #### [(八)Android之等级金字塔之Compose智能实现](https://juejin.cn/post/7468865451134091275) #### [(九)地图之Compose轻松绘制,可视化带点击事件,可扩展二次开发](https://juejin.cn/post/7485936146070356006) ## 本人其他开源文章: #### [那些大厂架构师是怎样封装网络请求的?](https://juejin.cn/post/7435904232597372940) #### [Kotlin+协程+Flow+Retrofit+OkHttp这么好用,不运行安装到手机可以调试接口吗?可以自己搭建一套网络请求工具](https://juejin.cn/post/7406675078810910761) #### [花式封装:Kotlin+协程+Flow+Retrofit+OkHttp +Repository,倾囊相授,彻底减少模版代码进阶之路](https://juejin.cn/post/7417847546323042345) #### [注解处理器在架构,框架中实战应用:MVVM中数据源提供Repository类的自动生成](https://juejin.cn/post/7392258195089162290) #### [Android串口,USB,打印机,扫码枪,支付盒子,键盘,鼠标,U盘等开发使用一网打尽](https://juejin.cn/post/7439231301869305910) #### [多台Android设备局域网下的数据备份如何实现?](https://juejin.cn/post/7444378661934055464) #### [轻松搞定Android蓝牙打印机,双屏异显及副屏分辨率适配解决办法](https://juejin.cn/post/7446820939943428107) #### [一个Kotlin版Demo带你入门JNI,NDK编程](https://juejin.cn/post/7452181029996380171) #### [元宵节前福利,神之操作,一键下载想要的同类型多个图片??](https://juejin.cn/post/7469991575277207602) #### [如何拦截其他Android应用程序播放器的原始音频数据自定义保存下来?](https://juejin.cn/post/7459720128983351337) #### [Android拦截其它播放声音:内录音,外录音,录屏,剪辑,混音,一键制作大片全搞定](https://juejin.cn/post/7472223022192836659) #### [Android之Apk全面瘦身,极致瘦身优化](https://juejin.cn/post/7483439484052258853) #### [电影电视剧网红广告屏自动轮播介绍视频特效制作,Compose轻松实现](https://juejin.cn/post/7491241868861554726) #### [Android下载进度百分比按钮,Compose轻松秒杀实现](https://juejin.cn/post/7493449430789095476) #### [Android监听开机自启,是否在前后台,锁屏界面,息屏后自动亮屏,一直保持亮屏](https://juejin.cn/post/7494083990069444648) #### [Android图片处理:多合一,多张生成视频,裁剪,滤镜色调,饱和度,亮度,缩放调整](https://juejin.cn/post/7496344493705510927) #### [Android投屏,设备远程协助,被远程服务浏览器上面操控屏幕如何实现?](https://juejin.cn/post/7500981295104000039) #### 感谢阅读,欢迎给给个星,你们的支持是我开源的动力 ## 欢迎光临: #### **[我的掘金地址](https://juejin.cn/user/356661835082573)** #### 关于我 **VX号:wgllss** ,如果想更多交流请加我VX ================================================ FILE: WX/WX-Code/WX-Host/app/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Host/app/build.gradle ================================================ plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) } android { namespace 'com.wgllss.dynamic.host' compileSdk libs.versions.compileSdk.get().toInteger() defaultConfig { applicationId "com.wgllss.dynamic.host.sample" minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 10000 versionName "1.0000" ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } signingConfigs { def password = "WXSample" def alias = "WXSample" def filePath = "./sign/WXSample.jks" debug { keyAlias alias keyPassword password storeFile file(filePath) storePassword(password) v1SigningEnabled true v2SigningEnabled true } release { keyAlias alias keyPassword password storeFile file(filePath) storePassword(password) v1SigningEnabled true v2SigningEnabled true } } buildTypes { debug { // 假如打包后运行闪退,可以在调试模式下打开混淆查看日志找出混淆问题 debuggable false minifyEnabled true // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled true // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.debug } release { debuggable false minifyEnabled true // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled true // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } applicationVariants.all { variant -> variant.outputs.all { outputFileName = "WXDynamicPlugin_Sample_${variant.buildType.name}.apk" } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } buildFeatures { buildConfig true // compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.7.0" } // lintOptions { // abortOnError false // } } dependencies { implementation libs.appcompat implementation libs.androidx.recyclerview implementation libs.google.material implementation libs.constraintlayout implementation project(path: ':Wgllss-Dynamic-Host-Version-Lib') implementation project(path: ':Wgllss-Dynamic-Host-Lib') // implementation project(path: ':Wgllss-Dynamic-Host-Download-Lib') // implementation project(path: ':Wgllss-Dynamic-Host-Constant-Lib') implementation project(path: ':wgllss-dynamic-host-skin-resource-lib') implementation project(path: ':wgllss-common-re-library') implementation project(path: ':wgllss-business-re-library') implementation project(path: ':wgllss-dynamic-host-library') // //compose // implementation(libs.androidx.activity.compose) // implementation(platform(libs.androidx.compose.bom)) // implementation(libs.androidx.ui) // implementation(libs.androidx.ui.graphics) // implementation(libs.androidx.ui.tooling.preview) // implementation(libs.androidx.material3) // implementation libs.androidx.constraintlayout.compose // implementation libs.androidx.runtime.livedata // implementation libs.coil.compose // implementation libs.androidx.navigation.compose // implementation libs.androidx.navigation.runtime.ktx // implementation libs.androidx.compose.material3.adaptive.navigation // implementation libs.androidx.compose.material3.adaptive // implementation libs.androidx.compose.material3.adaptive.layout // implementation libs.androidx.compose.material3.navigationSuite // implementation libs.androidx.compose.material3.windowSizeClass } ================================================ FILE: WX/WX-Code/WX-Host/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* #这个过滤器是谷歌推荐的算法,一般不做更改 -optimizationpasses 7 # 代码混淆压缩比,在0~7之间,默认为5,一般不做修改 -dontpreverify # 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。 -dontusemixedcaseclassnames #混合时不使用大小写混合,混合后的类名为小写 -verbose #包含有类名->混淆后类名的映射关系 日志记录 -keepattributes SourceFile,LineNumberTable # 保留代码行号 # Preserve some attributes that may be required for reflection. -keepattributes AnnotationDefault,*Annotation*,# 避免混淆注解 EnclosingMethod, # 避免混淆匿名类 InnerClasses, # 避免混淆内部类 RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeVisibleTypeAnnotations, Signature # 避免混淆泛型 -keep class com.google.android.material.** { *; } -keep class androidx.appcompat.view.ContextThemeWrapper { } -keep class androidx.fragment.app.FragmentActivity { } -keep class androidx.lifecycle.** { *; } -keep class com.wgllss.core.** { *; } -keep class com.wgllss.sample.** { *; } -keep class com.wgllss.dynamic.host.lib.**{} #-keep class com.wgllss.host.library.** { *; } #-keep class com.wgllss.dynamic.lib.** { *; } #-keep class com.wgllss.host.library.** { *; } #-keep class com.wgllss.plugin.library.** { *; } #-keep class com.wgllss.host.library.impl.** { *; } -keep class androidx.savedstate.** { *; } -keep class androidx.arch.core.internal.**{*;} -keep class com.wgllss.**{*;} -keep class android.**{*;} -keep class android.app.**{*;} -keep class androidx.**{*;} -keep class androidx.activity.**{*;} -keep class kotlinx.**{*;} -keep class coil.**{*;} -keep class com.tencent.mmkv.**{*;} -keep class com.google.android.**{*;} -keep class com.google.android.exoplayer2**{*;} -keep class com.google.gson.**{*;} -keep class retrofit2.**{*;} -keep class okhttp3.**{*;} -keep class okio.**{*;} -keep class com.bumptech.glide.**{*;} -keep class com.mcxtzhang.**{*;} -keep class com.hjq.**{*;} -keep class com.umeng.**{*;} -keep class org.jsoup.**{*;} -keep class res.**{*;} -keep class com.wgllss.sample.skin.**{*;} -keep class androidx.compose.**{*;} -keep class androidx.constraintlayout.compose.**{*;} -keep class * extends androidx.startup.Initializer{} # Fragment -keep class * extends androidx.fragment.app.Fragment{} -keep class * extends android.app.Application{} -keep class * extends androidx.lifecycle.LiveData{} -keep class * extends androidx.startup.InitializationProvider{} # keepclassmembers :防止类成员被移除或被混淆 -keepclassmembers class * { @android.webkit.JavascriptInterface ; } # 保留本地native方法不被混淆 -keepclasseswithmembernames class * { native ;} -dontnote androidx.** -dontwarn android.support.** -dontwarn androidx.** # 保留R下面的资源 -keep class **.R$* {*;} ## Android architecture components: Lifecycle # LifecycleObserver's empty constructor is considered to be unused by proguard -keepclassmembers class * implements androidx.lifecycle.LifecycleObserver { (...); } # ViewModel's empty constructor is considered to be unused by proguard -keepclassmembers class * extends androidx.lifecycle.ViewModel { (...); } -keepclassmembers class * extends androidx.lifecycle.LifecycleOwner { (...); } #-keepclassmembers class * extends androidx.savedstate.SavedStateRegistryOwner { # (...); #} # keep methods annotated with @OnLifecycleEvent even if they seem to be unused # (Mostly for LiveData.LifecycleBoundObserver.onStateChange(), but who knows) -keepclassmembers class * { @androidx.lifecycle.OnLifecycleEvent *; } # ViewBinding #-keep class androidx.databinding.DataBindingUtil{} -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet); } -keepclasseswithmembers class * { public (android.content.Context, android.util.AttributeSet, int); } ## Databinding #-dontwarn android.databinding.** #-keep class android.databinding.** { *; } # #-keep class android.content.Intent { *; } #-keep class android.os.Bundle { *; } # kotlin 相关 -dontwarn kotlin.** -keep class kotlin.** { *; } -keep interface kotlin.** { *; } ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/java/com/wgllss/dynamic/host/FaceImpl.kt ================================================ package com.wgllss.dynamic.host import android.text.TextUtils import com.wgllss.core.units.DeviceIdUtil import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.CDLFD import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.CLMD import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.COMMON import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.COMMON_BUSINESS import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.FIRST import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.HOME import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.MANAGER import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.RESOURCE_SKIN import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.RUNTIME import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.VERSION import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.WEB_ASSETS import com.wgllss.dynamic.host.lib.download.IDynamicDownLoadFace class FaceImpl : IDynamicDownLoadFace { private var baseXL: String = "" // override fun getHostL() = "http://192.168.3.108:8080/assets/WXDynamicPlugin/" // override fun getHostL() = "http://192.168.1.5:8080/assets/WXDynamicPlugin/" //todo 自己本地搭一个服务器,或者 自己服务器 或者 像我一样在gitee上面在自己的项目下建一个文件当作服务器 供下载, // 切记不要往往我的 gitee 项目上面推 override fun getHostL() = "https://gitee.com/wgllss888/WXDynamicPlugin/raw/master/WX-Resource/" /** 0:WXDynamicPlugin 动态化插件框架 理论上已经做到了可以完全不动宿主,但是如果一定要动宿主 可以提供以下思路: * 1:可以根据 宿主版本号得到 宿主版本支持的 的插件, * 2:当宿主必须 需要升级时,升级后原版本的插件不可用了,插件配置在新宿主版本文件夹下面,原宿主版本文件夹可可以先动态配置 在启动页 升级下载新的宿主 * @example 宿主版本 10000 版本支持的插件 放在服务端 WXDynamicPlugin/10000/ 文件夹下 20000版本的插件放在 WXDynamicPlugin/20000/下面 */ override fun getBaseL(): String { if (TextUtils.isEmpty(baseXL)) { baseXL = StringBuilder().append(getHostL()).append(DeviceIdUtil.getDeviceId()).append("/").append(BuildConfig.VERSION_CODE).append("/").toString() } return baseXL } override fun isDebug() = false override fun getOtherDLU() = realUrl("vc") override fun getMapDLU() = mutableMapOf( VERSION to realUrl("classes_version_dex"), COMMON to realUrl("classes_common_lib_dex"), WEB_ASSETS to realUrl("classes_business_web_res"), COMMON_BUSINESS to realUrl("classes_business_lib_dex"), HOME to realUrl("classes_home_dex"), RESOURCE_SKIN to realUrl("classes_common_skin_res"), RUNTIME to realUrl("classes_wgllss_dynamic_plugin_runtime"), MANAGER to realUrl("classes_manager_dex"), FIRST to realUrl("classes_loading_dex"), CLMD to realUrl("class_loader_impl_dex"), CDLFD to realUrl("classes_downloadface_impl_dex") ) override fun getLoadVersionClassName() = "com.wgllss.loader.version.LoaderVersionImpl" private fun realUrl(name: String) = StringBuilder().append(getBaseL()).append(name).toString() } ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/java/com/wgllss/dynamic/host/SampleApplication.kt ================================================ package com.wgllss.dynamic.host import android.app.Application import android.content.Context import com.wgllss.core.units.AppGlobals import com.wgllss.core.units.LogTimer import com.wgllss.dynamic.host.lib.impl.WXDynamicLoader class SampleApplication : Application() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) LogTimer.initTime(this) AppGlobals.sApplication = this WXDynamicLoader.instance.installPlugin(base, FaceImpl(), VersionImpl()) } } ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/java/com/wgllss/dynamic/host/VersionImpl.kt ================================================ package com.wgllss.dynamic.host import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant import com.wgllss.dynamic.host.lib.version.ILoaderVersion class VersionImpl : ILoaderVersion { override fun getV() = 1000 override fun isMustShowLoading() = false override fun getClfd() = Triple( "com.wgllss.dynamic.impl.ILoadHomeImpl", "loading", 1000 ) override fun getClmd() = Triple("", "", 0) override fun getCdlfd() = Triple("", "", 0) override fun getMapDLU() = linkedMapOf( DynamicPluginConstant.COMMON to Pair("classes_common_lib_dex", 1000), DynamicPluginConstant.WEB_ASSETS to Pair("classes_business_web_res", 1000), DynamicPluginConstant.COMMON_BUSINESS to Pair("classes_business_lib_dex", 1000), DynamicPluginConstant.RUNTIME to Pair("classes_wgllss_dynamic_plugin_runtime", 1000), DynamicPluginConstant.MANAGER to Pair("classes_manager_dex", 1000), DynamicPluginConstant.RESOURCE_SKIN to Pair("classes_common_skin_res", 1000), DynamicPluginConstant.HOME to Pair("classes_home_dex", 1000) ) // override fun getOthers() = mutableMapOf() override fun getOthers() = mutableMapOf( "classes_other_dex" to 1000, "classes_other_res" to 1000, "classes_other2_dex" to 1000, "classes_other2_res" to 1000 ) } ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/xml/backup_rules.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/xml/data_extraction_rules.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app/src/main/res/xml/network_security_config.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/.gitignore ================================================ /build /.gradle ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.kotlin.kapt) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.sample.library.re" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } kapt { generateStubs = true } } dependencies { implementation project(':wgllss-dynamic-host-skin-resource-lib') implementation libs.glide implementation libs.swiperefreshlayout implementation libs.startup.runtime implementation libs.squareup.retrofit implementation libs.com.squareup.okhttp3.logging.interceptor implementation libs.okhttp3.okhttp implementation libs.okio implementation libs.converter.gson implementation libs.converter.scalars //解析html implementation libs.org.jsoup.jsoup //noinspection UseTomlInstead implementation libs.palette.ktx //room 数据库 implementation libs.room.runtime kapt libs.room.compiler //mmkv implementation libs.mmkv implementation libs.exoplayer.core implementation libs.exoplayer.ui implementation libs.google.extension.mediasession } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/src/main/java/com/wgllss/sample/feature_system/globle/Constants.kt ================================================ package com.wgllss.sample.feature_system.globle import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions object Constants { const val MEDIA_ID_ROOT = "-1" const val MEDIA_TITLE_KEY = "MEDIA_TITLE_KEY" const val MEDIA_ID_KEY = "MEDIA_ID_KEY" const val MEDIA_AUTHOR_KEY = "MEDIA_AUTHOR_KEY" const val MEDIA_ARTNETWORK_URL_KEY = "MEDIA_ARTNETWORK_URL_KEY" const val MEDIA_URL_KEY = "MEDIA_URL_KEY" const val NOTIFICATION_LARGE_ICON_SIZE = 144 // px val defaultImgID = com.wgllss.host.skin.R.drawable.icon_loading val glideOptions = RequestOptions().fallback(com.wgllss.host.skin.R.drawable.icon_loading).diskCacheStrategy(DiskCacheStrategy.DATA) //单曲循环 const val MODE_PLAY_REPEAT_SONG = 2 //随机模式 const val MODE_PLAY_SHUFFLE_ALL = 1 //顺序播放重复队列 const val MODE_PLAY_REPEAT_QUEUE = 0 } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-business-re-library/src/test/java/com/wgllss/sample/ExampleUnitTest.kt ================================================ package com.wgllss.sample import org.junit.Test import org.junit.Assert.* /** * Example local unit test, which will execute on the development machine (host). * * See [testing documentation](http://d.android.com/tools/testing). */ class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.core.re" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1008 versionName "1.0.0.8" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } buildFeatures { dataBinding = true buildConfig true } lintOptions { abortOnError false } } dependencies { // implementation files('libs/com_wang_avi_library-2.1.3.aar') implementation libs.appcompat implementation libs.androidx.core.ktx implementation libs.androidx.lifecycle.runtime.ktx implementation libs.androidx.lifecycle.livedata.ktx implementation libs.androidx.lifecycle.viewmodel.ktx implementation libs.glide implementation libs.converter.gson //权限申请框架 implementation libs.xxpermissions implementation libs.androidx.activity.ktx implementation libs.androidx.fragment.ktx //compose implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) implementation libs.androidx.constraintlayout.compose implementation libs.androidx.runtime.livedata implementation libs.coil.compose implementation libs.androidx.navigation.compose implementation libs.androidx.navigation.runtime.ktx implementation libs.androidx.compose.material3.adaptive.navigation implementation libs.androidx.compose.material3.adaptive implementation libs.androidx.compose.material3.adaptive.layout implementation libs.androidx.compose.material3.navigationSuite implementation libs.androidx.compose.material3.windowSizeClass implementation libs.collapsing.toolbar.scaffold } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/dialog/CommonLoadingView.kt ================================================ package com.wgllss.core.dialog import android.content.Context import android.view.Gravity import android.view.View import android.widget.TextView import androidx.appcompat.app.AppCompatDialog import com.wgllss.core.re.R class CommonLoadingView : AppCompatDialog { private lateinit var txt_loading_text: TextView constructor (context: Context) : super(context, R.style.Loading) { setContentView(R.layout.common_loading) window?.run { txt_loading_text = findViewById(R.id.txt_loading_text) attributes.gravity = Gravity.CENTER } } fun show(showText: String) { txt_loading_text?.apply { if (showText.isNotEmpty()) { text = showText visibility = View.VISIBLE } else { visibility = View.GONE } } if (!isShowing()) { show() } } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/ex/ContextEX.kt ================================================ package com.wgllss.core.ex import android.app.Activity import android.content.Context import android.content.Intent import com.wgllss.core.re.R fun Context.launchActivity(intent: Intent) { startActivity(intent) if (this is Activity) overridePendingTransition(R.anim.anim_alpha_121, R.anim.anim_alpha_121) } fun Activity.finishActivity() { finish() overridePendingTransition(R.anim.anim_alpha_121, R.anim.anim_alpha_121) } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/ex/Flow.kt ================================================ package com.wgllss.core.ex import androidx.lifecycle.MutableLiveData import com.google.gson.JsonSyntaxException import com.wgllss.core.re.R import com.wgllss.core.units.AppGlobals import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flowOn import retrofit2.HttpException import java.io.InterruptedIOException import java.net.ConnectException import java.net.SocketException import java.net.SocketTimeoutException import java.net.UnknownHostException import java.util.concurrent.TimeoutException fun Throwable?.parseErrorString(): String = when (this) { is ConnectException, is SocketException -> { if (message?.contains("Network is unreachable") == true) getString(R.string.Mobilenetuseless_msg) if (message?.contains("Failed to connect to") == true) getString(R.string.failed_to_connect_to) else getString(R.string.ConnectException) } is HttpException -> { if (message?.contains("HTTP 50") == true) { message!!.substring(0, 8) } else { getString(R.string.HttpException) } } is InterruptedIOException -> { if (message?.contains("timeout") == true) getString(R.string.SocketTimeoutException) else getString(R.string.ConnectException) } is UnknownHostException -> getString(R.string.UnknownHostException) is JsonSyntaxException -> getString(R.string.JsonSyntaxException) is SocketTimeoutException, is TimeoutException -> getString(R.string.SocketTimeoutException) is IllegalArgumentException -> { if (message?.contains("baseUrl must end in ") == true) if (AppGlobals.sApplication.isNetWorkActive()) getString(R.string.HostBaseUrlError) else getString(R.string.Mobilenetuseless_msg) else message ?: getString(R.string.ElseNetException) } else -> getString(R.string.ElseNetException) } fun Flow.flowOnIOAndCatch(errorMsgLiveData: MutableLiveData? = null): Flow = flowOn(Dispatchers.IO) .catch { it.printStackTrace() errorMsgLiveData?.value = it.parseErrorString(); } suspend fun Flow.flowOnIOAndCatchAAndCollect() { flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 } fun getString(resID: Int) = AppGlobals.sApplication.getString(resID) //fun Flow.zip(flow2: Flow, flow3: Flow, transform: suspend (T1, T2, T3) -> R): Flow = channelFlow { // // val first: ReceiveChannel = produce { // this@zip.collect { // channel.send(it) // } // } // // val second: ReceiveChannel = produce { // flow2.collect { // channel.send(it) // } // } // // val third: ReceiveChannel = produce { // flow3.collect { // channel.send(it) // } // } // // (second as SendChannel<*>).invokeOnClose { // if (!first.isClosedForReceive) first.cancel(CancellationException()) // if (!third.isClosedForReceive) third.cancel(CancellationException()) // } // // (third as SendChannel<*>).invokeOnClose { // if (!first.isClosedForReceive) first.cancel(CancellationException()) // if (!second.isClosedForReceive) second.cancel(CancellationException()) // } // // val otherIterator = second.iterator() // val anotherIterator = third.iterator() // // try { // first.consumeEach { value -> // if (!otherIterator.hasNext() || !anotherIterator.hasNext()) { // return@consumeEach // } // send(transform(value, otherIterator.next(), anotherIterator.next())) // } // } catch (e: CancellationException) { // e.printStackTrace() // android.util.Log.e("TAG", "${e.message}") // // complete // } finally { // if (!second.isClosedForReceive) second.cancel(CancellationException()) // if (!third.isClosedForReceive) third.cancel(CancellationException()) // } //} ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/ex/NetWorkHelp.kt ================================================ package com.wgllss.core.ex import android.app.Application import android.content.Context import android.net.ConnectivityManager import android.net.NetworkCapabilities import android.os.Build fun Application.isNetWorkActive(): Boolean { val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val network = connectivityManager.activeNetwork ?: return false val activeNetwork = connectivityManager.getNetworkCapabilities(network) ?: return false return when { activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true activeNetwork.hasTransport(NetworkCapabilities.TRANSPORT_BLUETOOTH) -> true else -> false } } else { @Suppress("DEPRECATION") val networkInfo = connectivityManager.activeNetworkInfo ?: return false @Suppress("DEPRECATION") return networkInfo.isConnected } return true } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/permissions/PermissionInterceptor.kt ================================================ package com.wgllss.core.permissions import android.app.Activity import android.app.AlertDialog import android.content.DialogInterface import android.os.Build import com.hjq.permissions.* import com.wgllss.core.re.R import com.wgllss.core.widget.CommonToast open class PermissionInterceptor : IPermissionInterceptor { override fun grantedPermissions(activity: Activity?, allPermissions: List?, grantedPermissions: List?, all: Boolean, callback: OnPermissionCallback?) { if (callback == null) { return } callback.onGranted(grantedPermissions, all) } override fun deniedPermissions(activity: Activity, allPermissions: List, deniedPermissions: List, never: Boolean, callback: OnPermissionCallback?) { callback?.onDenied(deniedPermissions, never) if (never) { if (deniedPermissions.size == 1 && Permission.ACCESS_MEDIA_LOCATION == deniedPermissions[0]) { CommonToast.show(R.string.common_permission_media_location_hint_fail) return } showPermissionSettingDialog(activity, allPermissions, deniedPermissions, callback) return } if (deniedPermissions.size == 1) { val deniedPermission = deniedPermissions[0] if (Permission.ACCESS_BACKGROUND_LOCATION == deniedPermission) { CommonToast.show(R.string.common_permission_background_location_fail_hint) return } if (Permission.BODY_SENSORS_BACKGROUND == deniedPermission) { CommonToast.show(R.string.common_permission_background_sensors_fail_hint) return } } val message: String val permissionNames: List = PermissionNameConvert.permissionsToNames(activity, deniedPermissions) message = if (!permissionNames.isEmpty()) { activity.getString(R.string.common_permission_fail_assign_hint, PermissionNameConvert.listToString(permissionNames)) } else { activity.getString(R.string.common_permission_fail_hint) } CommonToast.show(message) } /** * 显示授权对话框 */ private fun showPermissionSettingDialog( activity: Activity?, allPermissions: List, deniedPermissions: List, callback: OnPermissionCallback? ) { if (activity == null || activity.isFinishing || Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed ) { return } val message: String val permissionNames: List = PermissionNameConvert.permissionsToNames(activity, deniedPermissions) message = if (!permissionNames.isEmpty()) { activity.getString(R.string.common_permission_manual_assign_fail_hint, PermissionNameConvert.listToString(permissionNames)) } else { activity.getString(R.string.common_permission_manual_fail_hint) } // 这里的 Dialog 只是示例,没有用 DialogFragment 来处理 Dialog 生命周期 AlertDialog.Builder(activity) .setTitle(R.string.common_permission_alert) .setMessage(message) .setPositiveButton(R.string.common_permission_goto_setting_page, DialogInterface.OnClickListener { dialog, which -> dialog.dismiss() XXPermissions.startPermissionActivity(activity, deniedPermissions, object : OnPermissionPageCallback { override fun onGranted() { if (callback == null) { return } callback.onGranted(allPermissions, true) } override fun onDenied() { showPermissionSettingDialog( activity, allPermissions, XXPermissions.getDenied(activity, allPermissions), callback ) } }) }) .show() } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/permissions/PermissionNameConvert.kt ================================================ package com.wgllss.core.permissions import android.content.Context import android.os.Build import com.hjq.permissions.Permission import com.wgllss.core.re.R object PermissionNameConvert { /** * 获取权限名称 */ fun getPermissionString(context: Context?, permissions: List): String { return listToString(permissionsToNames(context, permissions)) } /** * String 列表拼接成一个字符串 */ fun listToString(hints: List): String { if (hints == null || hints.isEmpty()) { return "" } val builder = StringBuilder() for (text in hints) { if (builder.toString().isEmpty()) { builder.append(text) } else { builder.append("、") .append(text) } } return builder.toString() } /** * 将权限列表转换成对应名称列表 */ fun permissionsToNames(context: Context?, permissions: List): List { val permissionNames: MutableList = ArrayList() if (context == null) { return permissionNames } if (permissions == null) { return permissionNames } for (permission in permissions) { when (permission) { Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE -> { val hint = context.getString(R.string.common_permission_storage) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.READ_MEDIA_IMAGES, Permission.READ_MEDIA_VIDEO -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val hint = context.getString(R.string.common_permission_image_and_video) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.READ_MEDIA_AUDIO -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val hint = context.getString(R.string.common_permission_audio) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.CAMERA -> { val hint = context.getString(R.string.common_permission_camera) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.RECORD_AUDIO -> { val hint = context.getString(R.string.common_permission_microphone) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_BACKGROUND_LOCATION -> { var hint: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !permissions.contains(Permission.ACCESS_FINE_LOCATION) && !permissions.contains(Permission.ACCESS_COARSE_LOCATION) ) { context.getString(R.string.common_permission_location_background) } else { context.getString(R.string.common_permission_location) } if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.BODY_SENSORS, Permission.BODY_SENSORS_BACKGROUND -> { var hint: String hint = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && !permissions.contains(Permission.BODY_SENSORS) ) { context.getString(R.string.common_permission_sensors_background) } else { context.getString(R.string.common_permission_sensors) } if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.BLUETOOTH_SCAN, Permission.BLUETOOTH_CONNECT, Permission.BLUETOOTH_ADVERTISE -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val hint = context.getString(R.string.common_permission_wireless_devices) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.NEARBY_WIFI_DEVICES -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val hint = context.getString(R.string.common_permission_wireless_devices) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.READ_PHONE_STATE, Permission.CALL_PHONE, Permission.ADD_VOICEMAIL, Permission.USE_SIP, Permission.READ_PHONE_NUMBERS, Permission.ANSWER_PHONE_CALLS -> { val hint = context.getString(R.string.common_permission_phone) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.GET_ACCOUNTS, Permission.READ_CONTACTS, Permission.WRITE_CONTACTS -> { val hint = context.getString(R.string.common_permission_contacts) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.READ_CALENDAR, Permission.WRITE_CALENDAR -> { val hint = context.getString(R.string.common_permission_calendar) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.READ_CALL_LOG, Permission.WRITE_CALL_LOG, Permission.PROCESS_OUTGOING_CALLS -> { val hint: String = context.getString(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) R.string.common_permission_call_log else R.string.common_permission_phone) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.ACTIVITY_RECOGNITION -> { val hint: String = context.getString(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) R.string.common_permission_activity_recognition_30 else R.string.common_permission_activity_recognition_29) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.ACCESS_MEDIA_LOCATION -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val hint = context.getString(R.string.common_permission_media_location) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.SEND_SMS, Permission.RECEIVE_SMS, Permission.READ_SMS, Permission.RECEIVE_WAP_PUSH, Permission.RECEIVE_MMS -> { val hint = context.getString(R.string.common_permission_sms) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.MANAGE_EXTERNAL_STORAGE -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { val hint = context.getString(R.string.common_permission_manage_storage) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.REQUEST_INSTALL_PACKAGES -> { val hint = context.getString(R.string.common_permission_install) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.SYSTEM_ALERT_WINDOW -> { val hint = context.getString(R.string.common_permission_window) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.WRITE_SETTINGS -> { val hint = context.getString(R.string.common_permission_setting) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.NOTIFICATION_SERVICE -> { val hint = context.getString(R.string.common_permission_notification) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.POST_NOTIFICATIONS -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val hint = context.getString(R.string.common_permission_post_notifications) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } } Permission.BIND_NOTIFICATION_LISTENER_SERVICE -> { val hint = context.getString(R.string.common_permission_notification_listener) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.PACKAGE_USAGE_STATS -> { val hint = context.getString(R.string.common_permission_task) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.SCHEDULE_EXACT_ALARM -> { val hint = context.getString(R.string.common_permission_alarm) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.ACCESS_NOTIFICATION_POLICY -> { val hint = context.getString(R.string.common_permission_not_disturb) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS -> { val hint = context.getString(R.string.common_permission_ignore_battery) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.BIND_VPN_SERVICE -> { val hint = context.getString(R.string.common_permission_vpn) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } Permission.PICTURE_IN_PICTURE -> { val hint = context.getString(R.string.common_permission_picture_in_picture) if (!permissionNames.contains(hint)) { permissionNames.add(hint) } } else -> {} } } return permissionNames } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/units/AppGlobals.kt ================================================ package com.wgllss.core.units import android.app.Application object AppGlobals { lateinit var sApplication: Application fun getApplication(): Application { if (!this::sApplication.isInitialized) { //去反射得到 try { val aClass = Class.forName("android.app.ActivityThread") //获取里面的currentApplication val currentApplication = aClass.getDeclaredMethod("currentApplication") sApplication = currentApplication.invoke(null, null) as Application } catch (e: Exception) { e.printStackTrace() } } return sApplication } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/units/DeviceIdUtil.kt ================================================ package com.wgllss.core.units import android.content.Context import android.os.Build import android.provider.Settings import java.security.MessageDigest import java.util.* object DeviceIdUtil { private const val isDeviceSelfSerial = false //自己设备测试序号 private val setsD = setOf("B05F9543937A5BA61901FC14F2540C62DA3E86C2", "2F6039397BA7EEC402E7036339963B23810CCBFD") //其他设备测试序号 命名可自定义 private const val ELSED = "dxde_m_p" fun getDeviceId(): String { if (isDeviceSelfSerial) { //todo 模拟序列号 return "2F6039397BA7EEC402E7036339963B23810CCBFD" } else { val context = AppGlobals.sApplication val sbDeviceId = StringBuilder() val androidID = getAndroidId(context) val id = getDeviceUUID(context).replace("-", "") if (androidID != null && androidID.isNotEmpty()) { sbDeviceId.append(androidID) sbDeviceId.append("|") } if (id != null && id.isNotEmpty()) { sbDeviceId.append(id) } if (sbDeviceId.toString().isNotEmpty()) { try { val hash = getHashByString(sbDeviceId.toString()) val sha1 = bytesToHex(hash!!) if (sha1 != null && sha1.isNotEmpty()) { LogTimer.LogE(this, "sha1:$sha1") return if (setsD.contains(sha1)) sha1 else ELSED } } catch (ex: Exception) { ex.printStackTrace() } } val s = sbDeviceId.toString() return if (setsD.contains(s)) s else ELSED } } private fun bytesToHex(data: ByteArray): String? { val sb = StringBuilder() var stmp: String for (n in data.indices) { stmp = Integer.toHexString(data[n].toInt() and 0xFF) if (stmp.length == 1) sb.append("0") sb.append(stmp) } return sb.toString().uppercase(Locale.CHINA) } private fun getHashByString(data: String): ByteArray? { return try { val messageDigest: MessageDigest = MessageDigest.getInstance("SHA1") messageDigest.reset() messageDigest.update(data.toByteArray(charset("UTF-8"))) messageDigest.digest() } catch (e: java.lang.Exception) { " ".toByteArray() } } private fun getDeviceUUID(context: Context): String { val sb = StringBuilder().apply { append("100001") append(Build.BOARD) append(Build.BRAND) append(Build.DEVICE) append(Build.HARDWARE) append(Build.ID) append(Build.MODEL) append(Build.PRODUCT) } val long = sb.toString().hashCode().toLong() return UUID(long, long).toString() } private fun getAndroidId(context: Context): String { try { return Settings.Secure.getString( context.contentResolver, Settings.Secure.ANDROID_ID ) } catch (ex: java.lang.Exception) { ex.printStackTrace() } return " " } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/units/LogTimer.kt ================================================ package com.wgllss.core.units import android.util.Log import com.wgllss.core.re.BuildConfig object LogTimer { var time: Long = System.currentTimeMillis() fun initTime(any: Any) { time = System.currentTimeMillis() } fun LogE(any: Any, tagName: String) { val cur = System.currentTimeMillis() val dis = cur - time if (BuildConfig.DEBUG) Log.e("${any.javaClass.simpleName}", " $tagName 耗时:${dis} ms") } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/java/com/wgllss/core/widget/CommonToast.kt ================================================ package com.wgllss.core.widget import android.content.Context import android.graphics.Color import android.graphics.drawable.GradientDrawable import android.os.Handler import android.os.Looper import android.util.TypedValue import android.view.Gravity import android.widget.LinearLayout import android.widget.TextView import android.widget.Toast import com.wgllss.core.units.AppGlobals import java.util.* class CommonToast { companion object { private val toastBackgroundId = -1 private val toastTextColorId = -1 private var lastDate: Date? = null // 提示时间间隔3秒钟 private val toastPeriod = 3 private var mToast: Toast? = null private var toastText: TextView? = null private val mHandler: Handler = Handler(Looper.getMainLooper()) private val r = Runnable { if (mToast != null) { mToast!!.cancel() mToast = null // toast隐藏后,将其置为null } if (toastText != null) { toastText = null } } /** * 显示toast * * @param strContent 显示内容 * @param widthRate 占屏幕宽度比例 0为 WRAP_CONTENT * @param heightRate 占屏幕高度比例 0为 WRAP_CONTENT * @param gravity 占屏幕位置 * @param delayMillis 延迟多少毫秒隐藏tost * @param isInToastPeriod isInToastPeriod 在规定的时间间隔里内是否显示 * @author :Atar * @createTime:2016-3-18上午10:19:13 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ @JvmStatic fun show(context: Context, strContent: String?, widthRate: Int, heightRate: Int, gravity: Int, offy: Int, delayMillis: Long, isInToastPeriod: Boolean) { show(context, strContent, widthRate, heightRate, gravity, offy, delayMillis, isInToastPeriod, 1, 0) } /** * 显示toast * * @param strContent 显示内容 * @param widthRate 占屏幕宽度比例 0为 WRAP_CONTENT * @param heightRate 占屏幕高度比例 0为 WRAP_CONTENT * @param gravity 占屏幕位置 * @param delayMillis 延迟多少毫秒隐藏tost * @param isInToastPeriod isInToastPeriod 在规定的时间间隔里内是否显示 * @param orientation 屏幕方向 * @param rotation 旋转角度 * @author :Atar * @createTime:2016-3-18上午10:19:13 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ @JvmStatic fun show(context: Context, strContent: String?, widthRate: Int, heightRate: Int, gravity: Int, offy: Int, delayMillis: Long, isInToastPeriod: Boolean, orientation: Int, rotation: Int) { try { if (isInToastPeriod) { return } mHandler!!.removeCallbacks(r) if (mToast == null || toastText == null) { // 只有mToast==null时才重新创建,否则只需更改提示文字 mToast = Toast(context) val toastLayout = LinearLayout(context) toastLayout.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT) toastLayout.orientation = LinearLayout.VERTICAL toastLayout.gravity = Gravity.CENTER toastText = TextView(context) val size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, context.resources.displayMetrics).toInt() var width = 0 var height = 0 if (orientation == 1) { // 1竖屏 val widthPixels = context.resources.displayMetrics.widthPixels width = if (widthRate == 0) { LinearLayout.LayoutParams.WRAP_CONTENT } else { widthPixels / widthRate } height = if (heightRate == 0) { LinearLayout.LayoutParams.WRAP_CONTENT } else { widthPixels / heightRate } toastText!!.layoutParams = LinearLayout.LayoutParams(width, height) toastLayout.rotation = rotation.toFloat() } else { val widthPixels = context.resources.displayMetrics.heightPixels width = if (widthRate == 0) { LinearLayout.LayoutParams.WRAP_CONTENT } else { widthPixels / widthRate } height = if (heightRate == 0) { LinearLayout.LayoutParams.WRAP_CONTENT } else { widthPixels / heightRate } toastText!!.layoutParams = LinearLayout.LayoutParams(width, height) toastLayout.rotation = rotation.toFloat() } toastText!!.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16f) toastText!!.setPadding(size, size, size, size) toastText!!.gravity = Gravity.CENTER if (toastBackgroundId != -1) { toastLayout.setBackgroundDrawable(context.resources.getDrawable(toastBackgroundId)) } else { setText(toastText!!) } if (toastTextColorId != -1) { toastText!!.setTextColor(context.resources.getColor(toastTextColorId)) } else { setText(toastText!!) } toastLayout.addView(toastText) mToast!!.view = toastLayout mToast!!.setGravity(gravity, 0, offy) mToast!!.duration = Toast.LENGTH_SHORT } if (toastText != null) { toastText!!.text = strContent } mHandler.postDelayed(r, delayMillis) // 延迟delayMillis耗秒隐藏toast try { mToast!!.show() } catch (e: Exception) { e.printStackTrace() } } catch (e: Exception) { } } @JvmStatic fun show(resID: Int) { show(AppGlobals.sApplication, AppGlobals.sApplication.resources.getString(resID), 0, 0, Gravity.CENTER, 0, 3000, false) } /** * 显示Toast * * @param strContent:提示肉容 * @author :Atar * @createTime:2014-6-25上午10:23:59 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ @JvmStatic fun show(strContent: String?) { show(AppGlobals.sApplication, strContent, 0, 0, Gravity.CENTER, 0, 3000, false) } @JvmStatic fun show(strContent: String?, dealyMills: Int) { show(AppGlobals.sApplication, strContent, 0, 0, Gravity.CENTER, 300, dealyMills.toLong(), false) } @JvmStatic fun show(strContent: String?, gravity: Int, offy: Int) { show(AppGlobals.sApplication, strContent, 0, 0, Gravity.CENTER, offy, 3000, false) } /** * 显示toast * * @param strContent 显示内容 * @param widthRate 占屏幕宽度比例 * @param heightRate 占屏幕高度比例 * @param gravity 占屏幕位置 * @param delayMillis 延迟多少毫秒隐藏tost * @author :Atar * @createTime:2016-3-18上午10:19:13 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ @JvmStatic fun show(strContent: String?, widthRate: Int, heightRate: Int, gravity: Int, delayMillis: Long) { show(AppGlobals.sApplication, strContent, widthRate, heightRate, gravity, 300, delayMillis, false) } /** * 在时间间隔内不作提示 * * @param strContent * @author :Atar * @createTime:2015-9-23下午3:33:03 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ @JvmStatic fun showWhihPeriod(strContent: String?) { show(AppGlobals.sApplication, strContent, 0, 0, Gravity.CENTER, 0, 3000, isInToastPeriod()) } /** * 在时间间隔内不作提示 * * @param strContent * @author :Atar * @createTime:2015-9-23下午3:33:03 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ fun showWhihPeriod(strContent: String?, delayMills: Int) { show(AppGlobals.sApplication, strContent, 0, 0, Gravity.CENTER, 0, delayMills.toLong(), isInToastPeriod()) } /** * @param mTextView * @author :Atar * @createTime:2015-9-23下午3:33:13 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ private fun setText(mTextView: TextView) { mTextView.setTextColor(Color.WHITE) val roundRadius = 8 val fillColor = Color.parseColor("#90000000") val gd = GradientDrawable() gd.setColor(fillColor) gd.cornerRadius = roundRadius.toFloat() mTextView.setBackgroundDrawable(gd) } /** * 是否在提示时间间隔内 * * @return * @author :Atar * @createTime:2014-11-12上午11:26:54 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ fun isInToastPeriod(): Boolean { val curDate = Date(System.currentTimeMillis()) // 获取当前时间 return if (curDate != null) { var lastTime: Long = 0 lastTime = if (lastDate == null) { 0 } else { lastDate!!.time } val timeLong = curDate.time - lastTime if (timeLong < toastPeriod * 1000) { true } else { lastDate = curDate false } } else { true } } fun dissMissToast() { if (mToast != null) { mToast!!.cancel() mToast = null // toast隐藏后,将其置为null } if (toastText != null) { toastText = null } mHandler?.removeCallbacksAndMessages(null) } } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/anim/anim_alpha_121.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/drawable/button_bg_transparent_helf.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/drawable/progressbar_shape.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/layout/common_loading.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/values/colors.xml ================================================ #FF000000 #FFFFFFFF ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/values/strings.xml ================================================ 未知错误异常 网络超时 网络超时 网络错误 网络错误 服务器异常 无网络连接 请求地址错误 当前网络不可用 无法连接到服务器 数据错误,json解析错误 授权提示 使用此功能需要先授予%s 授予 取消 授权提醒 授权失败,请正确授予权限 授权失败,请正确授予%s 获取权限失败,请手动授予权限 获取权限失败,请手动授予%s 获取后台定位权限失败,\n请您选择《始终允许》 获取后台传感器权限失败,\n请您选择《始终允许》 获取媒体位置权限失败\n请清除应用数据后重试 前往授权 日历权限 相机权限 通讯录权限 定位权限 后台定位权限 附近的设备权限 麦克风权限 电话权限 通话记录权限 身体传感器权限 后台身体传感器权限 健身运动权限 身体活动权限 读取媒体文件位置权限 短信权限 存储权限 发送通知权限 照片和视频权限 音乐和音频权限 所有文件访问权限 安装应用权限 悬浮窗权限 修改系统设置权限 通知权限 通知栏监听权限 查看使用情况权限 查看闹钟提醒权限 勿扰权限 忽略电池优化权限 画中画权限 \tVPN\t权限 ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-common-re-library/src/main/res/values/themes.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.host.library" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { implementation project(path: ':wgllss-dynamic-host-skin-resource-lib') implementation project(path: ':wgllss-common-re-library') implementation project(path: ':wgllss-business-re-library') } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/consumer-rules.pro ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/src/androidTest/java/com/wgllss/host/library/ExampleInstrumentedTest.kt ================================================ package com.wgllss.host.library import android.support.test.InstrumentationRegistry import android.support.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith import org.junit.Assert.* /** * Instrumented test, which will execute on an Android device. * * See [testing documentation](http://d.android.com/tools/testing). */ @RunWith(AndroidJUnit4::class) class ExampleInstrumentedTest { @Test fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getInstrumentation().targetContext assertEquals("com.wgllss.host.library.test", appContext.packageName) } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-library/src/test/java/com/wgllss/host/library/ExampleUnitTest.kt ================================================ package com.wgllss.host.library import org.junit.Test import org.junit.Assert.* /** * Example local unit test, which will execute on the development machine (host). * * See [testing documentation](http://d.android.com/tools/testing). */ class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) } } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/build.gradle ================================================ plugins { alias(libs.plugins.android.library) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.host.skin" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation libs.appcompat implementation libs.google.material } ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/ic_baseline_pause_36.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/ic_baseline_play_arrow_36.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/ic_baseline_skip_next_36.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/ic_baseline_skip_previous_36.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/splash_preview.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/drawable/splash_preview_dark.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values/colors.xml ================================================ #FF000000 #FFFFFFFF #FF3300 #FFFFFF #005e91 #FF000000 #008e99 ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values/dimens.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values/ids.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values/strings.xml ================================================ WXDynamicPlugin --:-- %d:%02d ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values/themes.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values-night/colors.xml ================================================ #FF000000 #FFFFFFFF #FF3300 #B0B0B0 #007A00 #222222 #B0B0B0 ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values-night/themes.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values-v27/themes.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Host/app-lib/wgllss-dynamic-host-skin-resource-lib/src/main/res/values-v29/themes.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.kotlin.kapt) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.core" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1008 versionName "1.0.0.8" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } buildFeatures { buildConfig = true dataBinding = true } kapt { generateStubs = true } lintOptions { abortOnError false } } dependencies { compileOnly project(':wgllss-common-re-library') compileOnly libs.appcompat compileOnly libs.androidx.recyclerview compileOnly libs.google.material compileOnly libs.androidx.lifecycle.runtime.ktx compileOnly libs.androidx.lifecycle.livedata.ktx compileOnly libs.androidx.lifecycle.viewmodel.ktx compileOnly libs.androidx.activity.ktx compileOnly libs.androidx.fragment.ktx compileOnly libs.androidx.core.ktx compileOnly libs.swiperefreshlayout compileOnly libs.androidx.navigation.fragment.ktx compileOnly libs.androidx.navigation.ui.ktx compileOnly libs.glide kapt libs.glide.compiler //compose compileOnly libs.androidx.activity.compose } def createCopyTask(buildType) { def workingDirPath = rootProject.ext.workingDirPath def outputFile = file("${workingDirPath}classes_common_lib.jar") def outputDexFile = file("${workingDirPath}classes_common_lib_dex.jar") def lastOutputDexFile = file("${rootProject.getBuildDir()}/classes_common_lib_dex") if (lastOutputDexFile.exists()) { lastOutputDexFile.delete() } if (outputDexFile.exists()) { outputDexFile.delete() } if (outputFile.exists()) { outputFile.delete() } def inputFile = file("${getProject().getBuildDir()}/intermediates/aar_main_jar/${buildType}/sync${buildType}LibJars/classes.jar") def copyTask = tasks.create("assembleCopy${buildType.capitalize()}", Copy) { group = 'other' description = "复制${name}到dx环境中." from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn("assemble${buildType.capitalize()}") def assembleDxCommand = tasks.create("assembleDxCommand", Exec) { group = 'other' description = "${name}到dx执行中..." workingDir workingDirPath if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) { it.commandLine 'cmd', '/c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } else { it.commandLine 'bash', '-c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } // it.commandLine 'cmd', "/c", "d8 --output ${outputDexFile.name} ${outputFile.name}" }.dependsOn(copyTask.name) return tasks.create("assembleDxCommandAndCopy") { doLast { copy { from(outputDexFile.getParent()) { include(outputDexFile.name) rename { lastOutputDexFile.name } } into(lastOutputDexFile.getParent()) } } }.dependsOn(assembleDxCommand.name) } tasks.whenTaskAdded { task -> // if (task.name == "assembleDebug") { // createCopyTask("Debug") // } if (task.name == "assembleRelease") { createCopyTask("Release") } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseActivity.kt ================================================ package com.wgllss.core.activity import android.os.Bundle import androidx.activity.compose.setContent import androidx.annotation.Nullable import androidx.compose.runtime.Composable import androidx.fragment.app.FragmentActivity import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStore import com.wgllss.core.dialog.CommonLoadingView import com.wgllss.core.ex.finishActivity import com.wgllss.core.units.StatusBarUtil import com.wgllss.core.widget.CommonToast abstract class BaseActivity : FragmentActivity() { private var loading: CommonLoadingView? = null private var initFlag = false open fun hasNavigationBarStatusBarTranslucent() = true override fun onCreate(savedInstanceState: Bundle?) { if (hasNavigationBarStatusBarTranslucent()) StatusBarUtil.setStatusBarTranslucent(this) beforeSuperOnCreate(savedInstanceState); super.onCreate(savedInstanceState) initX(savedInstanceState) } protected open fun initX(savedInstanceState: Bundle?) { initControl(savedInstanceState) bindEvent() initValue() } override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { if (!initFlag) { initFlag = true lazyInitValue() } } } fun onToast(content: String) { CommonToast.show(content); } //是否loading open fun isShowloading(): Boolean? { return loading?.isShowing() } open fun showloading(showText: String?) { if (null == loading) loading = CommonLoadingView(this) if (isShowloading() == true) return if (showText != null) loading?.show(showText) } open fun hideLoading() { loading?.dismiss() loading = null } override fun onDestroy() { hideLoading() super.onDestroy() } override fun onBackPressed() { super.onBackPressed() finishActivity() } open fun beforeSuperOnCreate(savedInstanceState: Bundle?) {} open abstract fun initControl(savedInstanceState: Bundle?) open abstract fun bindEvent() open abstract fun initValue() open fun lazyInitValue() {} private var exitTime: Long = 0 protected open fun exitApp() { if (System.currentTimeMillis() - exitTime > 2000) { onToast("再按一次退出程序") exitTime = System.currentTimeMillis() } else { WActivityManager.exitApplication() } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseMVVMActivity.kt ================================================ package com.wgllss.core.activity import android.os.Bundle import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.databinding.DataBindingUtil import androidx.databinding.ViewDataBinding import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import com.wgllss.core.units.WLog import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType import kotlin.system.measureTimeMillis /** * contentLayoutId 不传给父类,否则 binding = DataBindingUtil.setContentView(this, contentLayoutId) 设置一次 * 父类里面ComponentActivity还要设置一次 共2次 见下 * * * @Override * protected void onCreate(@Nullable Bundle savedInstanceState) { * // Restore the Saved State first so that it is available to * // OnContextAvailableListener instances * mSavedStateRegistryController.performRestore(savedInstanceState); * mContextAwareHelper.dispatchOnContextAvailable(this); * super.onCreate(savedInstanceState); * mActivityResultRegistry.onRestoreInstanceState(savedInstanceState); * ReportFragment.injectIfNeededIn(this); * if (mContentLayoutId != 0) { * setContentView(mContentLayoutId); * } * } */ abstract class BaseMVVMActivity(@LayoutRes private val contentLayoutId: Int) : BaseActivity() { protected val viewModel by lazyViewModels() protected lateinit var binding: VB override fun initControl(savedInstanceState: Bundle?) { val time = measureTimeMillis { binding = DataBindingUtil.setContentView(this, contentLayoutId) binding.lifecycleOwner = this@BaseMVVMActivity } WLog.e(this, "time:${time}") } override fun bindEvent() { viewModel?.run { showUIDialog.observe(this@BaseMVVMActivity, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(this@BaseMVVMActivity, Observer { onToast(it) }) } } override fun initValue() { } @MainThread inline fun lazyViewModels(): Lazy { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseViewModePluginActivity.kt ================================================ package com.wgllss.core.activity import android.os.Bundle import androidx.annotation.MainThread import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import com.wgllss.core.units.ResourceUtils import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType /** * contentLayoutId 不传给父类,否则 binding = DataBindingUtil.setContentView(this, contentLayoutId) 设置一次 * 父类里面ComponentActivity还要设置一次 共2次 见下 * * * @Override * protected void onCreate(@Nullable Bundle savedInstanceState) { * // Restore the Saved State first so that it is available to * // OnContextAvailableListener instances * mSavedStateRegistryController.performRestore(savedInstanceState); * mContextAwareHelper.dispatchOnContextAvailable(this); * super.onCreate(savedInstanceState); * mActivityResultRegistry.onRestoreInstanceState(savedInstanceState); * ReportFragment.injectIfNeededIn(this); * if (mContentLayoutId != 0) { * setContentView(mContentLayoutId); * } * } */ abstract class BaseViewModePluginActivity(protected val layoutName: String, packageNamePlugin: String) : BaseViewPluginResActivity(packageNamePlugin) { protected val viewModel by lazyViewModels() override fun initControl(savedInstanceState: Bundle?) { ResourceUtils.setContentLayout(this, resourcesPlugin, layoutName, packageNamePlugin) } override fun bindEvent() { viewModel?.run { showUIDialog.observe(this@BaseViewModePluginActivity, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(this@BaseViewModePluginActivity, Observer { onToast(it) }) } } override fun initValue() { } @MainThread inline fun lazyViewModels(): Lazy { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseViewModelActivity.kt ================================================ package com.wgllss.core.activity import android.os.Bundle import androidx.annotation.MainThread import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType /** * contentLayoutId 不传给父类,否则 binding = DataBindingUtil.setContentView(this, contentLayoutId) 设置一次 * 父类里面ComponentActivity还要设置一次 共2次 见下 * * * @Override * protected void onCreate(@Nullable Bundle savedInstanceState) { * // Restore the Saved State first so that it is available to * // OnContextAvailableListener instances * mSavedStateRegistryController.performRestore(savedInstanceState); * mContextAwareHelper.dispatchOnContextAvailable(this); * super.onCreate(savedInstanceState); * mActivityResultRegistry.onRestoreInstanceState(savedInstanceState); * ReportFragment.injectIfNeededIn(this); * if (mContentLayoutId != 0) { * setContentView(mContentLayoutId); * } * } */ abstract class BaseViewModelActivity(packageNamePlugin: String) : BaseViewPluginResActivity(packageNamePlugin) { protected val viewModel by lazyViewModels() override fun bindEvent() { viewModel?.run { showUIDialog.observe(this@BaseViewModelActivity, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(this@BaseViewModelActivity, Observer { onToast(it) }) } } override fun initValue() { } @MainThread inline fun lazyViewModels(): Lazy { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseViewModelClassActivity.kt ================================================ package com.wgllss.core.activity import android.os.Bundle import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import com.wgllss.core.viewmodel.BaseViewModel /** * contentLayoutId 不传给父类,否则 binding = DataBindingUtil.setContentView(this, contentLayoutId) 设置一次 * 父类里面ComponentActivity还要设置一次 共2次 见下 * * * @Override * protected void onCreate(@Nullable Bundle savedInstanceState) { * // Restore the Saved State first so that it is available to * // OnContextAvailableListener instances * mSavedStateRegistryController.performRestore(savedInstanceState); * mContextAwareHelper.dispatchOnContextAvailable(this); * super.onCreate(savedInstanceState); * mActivityResultRegistry.onRestoreInstanceState(savedInstanceState); * ReportFragment.injectIfNeededIn(this); * if (mContentLayoutId != 0) { * setContentView(mContentLayoutId); * } * } */ abstract class BaseViewModelClassActivity : BaseActivity() { val viewModel by lazy { ViewModelProvider(viewModelStore, defaultViewModelProviderFactory).get(getViewModelClass()) } override fun bindEvent() { viewModel?.run { showUIDialog.observe(this@BaseViewModelClassActivity, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(this@BaseViewModelClassActivity, Observer { onToast(it) }) } } override fun initValue() { } open abstract fun getViewModelClass(): Class } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/BaseViewPluginResActivity.kt ================================================ package com.wgllss.core.activity import android.content.Context import android.content.res.Resources import android.graphics.drawable.Drawable import com.wgllss.core.fragment.BasePluginResFragment import com.wgllss.core.units.ResourceUtils /** * contentLayoutId 不传给父类,否则 binding = DataBindingUtil.setContentView(this, contentLayoutId) 设置一次 * 父类里面ComponentActivity还要设置一次 共2次 见下 * * * @Override * protected void onCreate(@Nullable Bundle savedInstanceState) { * // Restore the Saved State first so that it is available to * // OnContextAvailableListener instances * mSavedStateRegistryController.performRestore(savedInstanceState); * mContextAwareHelper.dispatchOnContextAvailable(this); * super.onCreate(savedInstanceState); * mActivityResultRegistry.onRestoreInstanceState(savedInstanceState); * ReportFragment.injectIfNeededIn(this); * if (mContentLayoutId != 0) { * setContentView(mContentLayoutId); * } * } */ abstract class BaseViewPluginResActivity(protected val packageNamePlugin: String) : BaseActivity() { protected lateinit var resourcesPlugin: Resources override fun attachBaseContext(newBase: Context) { super.attachBaseContext(newBase) getPluginResources()?.let { resourcesPlugin = it } } override fun onStart() { super.onStart() onChangeSkin(getSkinResources()) } abstract fun getSkinResources(): Resources abstract fun getPluginResources(): Resources? protected fun getPluginDrawable(resName: String): Drawable = ResourceUtils.getPluginDrawable(resourcesPlugin, resName, packageNamePlugin) protected fun getPluginDrawable(skinRes: Resources, resName: String, skinPackageName: String): Drawable = ResourceUtils.getPluginDrawable(skinRes, resName, skinPackageName) protected fun getPluginID(resName: String) = ResourceUtils.getPluginID(resourcesPlugin, resName, packageNamePlugin) protected fun getPluginID(skinRes: Resources, resName: String, skinPackageName: String) = ResourceUtils.getPluginID(skinRes, resName, skinPackageName) open fun onChangeSkin(skinRes: Resources) { } open fun callChangeSkin(skinRes: Resources) { onChangeSkin(skinRes) supportFragmentManager.fragments.forEach { if (it.isAdded && it is BasePluginResFragment) { it.callChangeSkin(skinRes) } } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/WActivityManager.kt ================================================ package com.wgllss.core.activity import android.app.Activity import android.os.Process import com.wgllss.core.ex.finishActivity import java.lang.reflect.Field import java.lang.reflect.Method object WActivityManager { fun getActivitys(block: (it: Activity) -> Any) { try { val activityThread = Class.forName("android.app.ActivityThread") val currentActivityThread: Method = activityThread.getDeclaredMethod("currentActivityThread") currentActivityThread.isAccessible = true //获取主线程对象 val activityThreadObject: Any = currentActivityThread.invoke(null) val mActivitiesField: Field = activityThread.getDeclaredField("mActivities") mActivitiesField.isAccessible = true val mActivities = mActivitiesField[activityThreadObject] as Map mActivities.forEach { val activityClientRecordClass: Class<*> = it.value.javaClass val activityField = activityClientRecordClass.getDeclaredField("activity") activityField.isAccessible = true activityField[it.value]?.let { block.invoke(it as Activity) } } } catch (e: java.lang.Exception) { e.printStackTrace() } } fun popAllActivity() { getActivitys() { it.finishActivity() } } fun exitApplication() { object : Thread() { override fun run() { super.run() popAllActivity() Process.killProcess(Process.myPid()) System.exit(0) // 常规java、c#的标准退出法,返回值为0代表正常退出 } }.start() } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/activity/compose/BaseComposeActivity.kt ================================================ package com.wgllss.core.activity.compose import androidx.activity.ComponentActivity open class BaseComposeActivity : ComponentActivity(){ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/adapter/BasePagerAdapter.kt ================================================ package com.wgllss.core.adapter import android.view.View import android.view.ViewGroup import androidx.viewpager.widget.PagerAdapter class BasePagerAdapter(val mViews: MutableList) : PagerAdapter() { override fun getCount() = mViews?.size ?: 0 override fun isViewFromObject(view: View, obj: Any) = view === obj override fun destroyItem(container: ViewGroup, position: Int, obj: Any) { mViews?.takeIf { it.size > 0 }?.let { container.removeView(it[position]) } } override fun instantiateItem(container: ViewGroup, position: Int): Any { container.addView(mViews[position]) return mViews[position] } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/adapter/BasePluginRecyclerAdapter.kt ================================================ package com.wgllss.core.adapter import android.content.Context import android.content.res.Resources import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView abstract class BasePluginRecyclerAdapter(protected val re: Resources, private val packageName: String) : RecyclerView.Adapter() { var context: Context? = null protected lateinit var mData: MutableList lateinit var skinRes: Resources fun notifyData(mData: MutableList, skinRes: Resources) { if (mData == null) { this.mData = mutableListOf() } else { this.mData = mData } this.skinRes = skinRes notifyDataSetChanged() } fun notifySkinRes(skinRes: Resources) { this.skinRes = skinRes notifyDataSetChanged() } fun removeItem(position: Int) { mData?.takeIf { it.size > position }?.run { removeAt(position) notifyDataSetChanged() } } fun clearList() { mData?.run { clear() notifyDataSetChanged() } } override fun getItemCount(): Int = if (!this::mData.isInitialized) 0 else mData.size override fun getItemId(position: Int): Long { return position.toLong() } fun getItem(position: Int): T = mData[position] protected abstract fun getLayoutResIdName(viewType: Int): String override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseBindingViewHolder { if (context == null) { context = parent.context } val layoutID = re.getIdentifier(getLayoutResIdName(viewType), "layout", packageName) val xmlResourceParser = re.getLayout(layoutID) val view = LayoutInflater.from(context).inflate(xmlResourceParser, parent, false) return BaseBindingViewHolder(view) } override fun onBindViewHolder(holder: BaseBindingViewHolder, position: Int) { val item = getItem(position) onBindItem(context!!, item, holder, position) } fun findViewByID(contentView: View, resourcesPlugin: Resources, IDResName: String): T { val ID = resourcesPlugin.getIdentifier(IDResName, "id", packageName) return contentView.findViewById(ID) } fun getPluginColorID(IDResName: String): Int { val ID = re.getIdentifier(IDResName, "color", packageName) return ID } fun getPluginColor(IDResName: String): Int { return re.getColor(getPluginColorID(IDResName)) } fun getPluginColor(re: Resources, IDResName: String, packageName: String): Int { return re.getColor(getPluginColorID(re, IDResName, packageName)) } fun getPluginColorID(re: Resources, IDResName: String, packageName: String): Int { val ID = re.getIdentifier(IDResName, "color", packageName) return ID } protected abstract fun onBindItem(context: Context, item: T, holder: RecyclerView.ViewHolder, position: Int) class BaseBindingViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/adapter/BaseRecyclerAdapter.kt ================================================ package com.wgllss.core.adapter import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes import androidx.recyclerview.widget.RecyclerView abstract class BaseRecyclerAdapter : RecyclerView.Adapter() { var context: Context? = null private lateinit var mData: MutableList fun notifyData(mData: MutableList) { if (mData == null) { this.mData = mutableListOf() } else { this.mData = mData } notifyDataSetChanged() } fun removeItem(position: Int) { mData?.takeIf { it.size > position }?.run { removeAt(position) notifyDataSetChanged() } } fun clearList() { mData?.run { clear() notifyDataSetChanged() } } override fun getItemCount(): Int = if (!this::mData.isInitialized) 0 else mData.size override fun getItemId(position: Int): Long { return position.toLong() } fun getItem(position: Int): T = mData[position] override fun onBindViewHolder(holder: BaseBindingViewHolder, position: Int) { val item = getItem(position) onBindItem(context!!, item, holder, position) } protected abstract fun onBindItem(context: Context, item: T, holder: RecyclerView.ViewHolder, position: Int) class BaseBindingViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/adapter/ViewPage2ChildFragmentAdapter.kt ================================================ package com.wgllss.core.adapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle import androidx.viewpager2.adapter.FragmentStateAdapter class ViewPage2ChildFragmentAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) { lateinit var list: MutableList fun notifyData(mData: MutableList) { if (mData == null) { list = mutableListOf() } else { this.list = mData } notifyDataSetChanged() } override fun getItemCount() = if (!this::list.isInitialized) 0 else list.size override fun createFragment(position: Int) = list[position] } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/data/DialogBean.kt ================================================ package com.wgllss.core.data data class DialogBean(var msg:String, var isShow:Boolean){ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/Context.kt ================================================ package com.wgllss.core.ex import android.app.Activity import android.app.ActivityManager import android.content.Context import android.graphics.Rect import android.os.Process import android.util.DisplayMetrics import android.util.Log import android.util.TypedValue import android.view.WindowManager import androidx.annotation.StyleRes import androidx.appcompat.view.ContextThemeWrapper import java.lang.reflect.Field fun Context.toTheme(@StyleRes style: Int) = ContextThemeWrapper(this, style) fun Context.dpToPx(dp: Float) = dp * resources.displayMetrics.density fun Context.pxToDp(px: Float) = px / resources.displayMetrics.density fun Context.dp2px(dipValue: Float) = (dipValue * resources.displayMetrics.density + 0.5f).toInt() fun Context.dpToPxInt(dp: Float) = (dpToPx(dp) + 0.5f).toInt().toFloat() fun Context.pxToDpCeilInt(px: Float) = (pxToDp(px) + 0.5f).toInt().toFloat() fun Context.getIntToDip(intSize: Float) = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, intSize, resources.displayMetrics) fun Activity.getStatusHight() = window.decorView.getWindowVisibleDisplayFrame(Rect()) /** * 得到状态栏高度 * * @return */ fun Activity.getStatusBarHeight(): Int { /* * 方法一,荣耀3c无效 Rect frame = new Rect(); act.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); int statusBarHeight = frame.top; return statusBarHeight; */ /* * 方法二,荣耀3c无效 Rect rectgle= new Rect(); Window window= act.getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); int StatusBarHeight= rectgle.top; int contentViewTop= * window.findViewById(Window.ID_ANDROID_CONTENT).getTop(); int statusBar = contentViewTop - StatusBarHeight; return statusBar; */ // 方法三,荣耀3c有效 var c: Class<*>? = null var obj: Any? = null var field: Field? = null var x = 0 var sbar = 0 try { c = Class.forName("com.android.internal.R\$dimen") obj = c.newInstance() field = c.getField("status_bar_height") x = field[obj].toString().toInt() sbar = resources.getDimensionPixelSize(x) return sbar } catch (e1: Exception) { e1.printStackTrace() } return 0 } fun Activity.getDensity(): Float { val dm = DisplayMetrics() windowManager.defaultDisplay.getMetrics(dm) val density: Float = dm.density//屏幕的密度density return density } fun Activity.getDensityDpi(): Int { val dm = DisplayMetrics() windowManager.defaultDisplay.getMetrics(dm) val density: Int = dm.densityDpi//屏幕的密度density return density } /** * 获得屏幕宽度 * * @param context * @return */ fun Context.getScreenWidth(): Int { val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager val outMetrics = DisplayMetrics() wm.defaultDisplay.getMetrics(outMetrics) return outMetrics.widthPixels } /** * 获得屏幕高度 * * @param context * @return */ fun Context.getScreenHeight(): Int { val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager val outMetrics = DisplayMetrics() wm.defaultDisplay.getMetrics(outMetrics) return outMetrics.heightPixels } //获取底部导航栏高度 fun Activity.getNavigationBarHeight(): Int { val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") return resources.getDimensionPixelSize(resourceId) } fun Context.isUIProcess(): Boolean { try { val am: ActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val processInfos: List = am.runningAppProcesses val mainProcessName: String = packageName val myPid = Process.myPid() for (info in processInfos) { if (info.pid === myPid && mainProcessName == info.processName) { return true } } } catch (e: Exception) { e.printStackTrace() } return false } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/Fragment.kt ================================================ package com.wgllss.core.ex import android.content.Context import android.view.View import android.view.inputmethod.InputMethodManager import androidx.annotation.IdRes import androidx.fragment.app.Fragment fun Fragment.switchFragment(fragment: Fragment, mCurrentFragmentTAG: StringBuilder?, @IdRes idRes: Int) { if (mCurrentFragmentTAG == null || fragment.javaClass.simpleName !== mCurrentFragmentTAG.toString()) { childFragmentManager.apply { val f = findFragmentByTag(mCurrentFragmentTAG.toString()) beginTransaction()?.let { f?.let { f -> it.hide(f) } fragment?.apply { if (!isAdded) { userVisibleHint = true; it.add(idRes, this, javaClass.simpleName).show(this) } else { it.show(this) } } it.commitAllowingStateLoss() } } } } fun Fragment.setFramgment(fragment: Fragment, layoutID: Int) { childFragmentManager.beginTransaction()?.let { fragment?.apply { if (!isAdded) { userVisibleHint = true; it.add(layoutID, this, javaClass.simpleName).show(this) } else { it.show(this) } } it.commitAllowingStateLoss() } } fun Fragment.HideSoftInputFromWindow(v: View) { (activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)?.hideSoftInputFromWindow(v.windowToken, 0); //强制隐藏键盘 } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/FragmentActivity.kt ================================================ package com.wgllss.core.ex import android.content.Context import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager import androidx.activity.ComponentActivity import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.IdRes import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity fun FragmentActivity.switchFragment(fragment: Fragment, mCurrentFragmentTAG: StringBuilder?, @IdRes idRes: Int) { if (mCurrentFragmentTAG == null || fragment.javaClass.simpleName !== mCurrentFragmentTAG.toString()) { supportFragmentManager.apply { val f = findFragmentByTag(mCurrentFragmentTAG.toString()) beginTransaction()?.let { f?.let { f -> it.hide(f) } fragment?.apply { if (!isAdded) { userVisibleHint = true; it.add(idRes, this, javaClass.simpleName).show(this) } else { it.show(this) } } it.commitAllowingStateLoss() } } } } fun FragmentActivity.setFramgment(fragment: Fragment, layoutID: Int) { supportFragmentManager.beginTransaction()?.let { fragment?.apply { if (!isAdded) { userVisibleHint = true; it.add(layoutID, this, javaClass.simpleName).show(this) } else { it.show(this) } } it.commitAllowingStateLoss() } } fun FragmentActivity.hideSoftInputFromWindow(v: View) { (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)?.hideSoftInputFromWindow(v.windowToken, 0); //强制隐藏键盘 } fun FragmentActivity.setFullScreen() { window.apply { addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ) } } fun ComponentActivity.registerForActivityResultPermissionsLaunch(permission: Array, blockPerSuccess: () -> Unit, blockPerFail: () -> Unit = {}) { registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { it -> var successCount = 0 it.forEach { k, v -> if (k != null && v) { successCount++ } } if (successCount == permission.size) { blockPerSuccess() } else { blockPerFail() } }.launch(permission) } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/ImageView.kt ================================================ package com.wgllss.core.ex import android.widget.ImageView import com.bumptech.glide.Glide fun ImageView.loadUrl(url: String) { Glide.with(context).load(url).into(this) } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/SwipeRefreshLayout.kt ================================================ package com.wgllss.core.ex import androidx.swiperefreshlayout.widget.SwipeRefreshLayout fun SwipeRefreshLayout.initColors() { setColorSchemeResources( android.R.color.holo_purple, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light ) } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/ex/ViewModel.kt ================================================ package com.wgllss.core.ex import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch fun ViewModel.flowAsyncWorkOnLaunch(flowAsyncWork: suspend () -> Flow) { viewModelScope.launch { flowAsyncWork.invoke().flowOnIOAndCatchAAndCollect() } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/fragment/BaseFragment.kt ================================================ package com.wgllss.core.fragment import androidx.annotation.LayoutRes import androidx.fragment.app.Fragment import com.wgllss.core.activity.BaseActivity import com.wgllss.core.widget.CommonToast open class BaseFragment(@LayoutRes private val contentLayoutId: Int) : Fragment(contentLayoutId) { fun onToast(toastContent: String?) { CommonToast.show(toastContent) } fun showloading() { showloading("请稍候...") } //是否loading protected fun isShowloading(): Boolean? { return if (activity != null && activity is BaseActivity) (activity as BaseActivity)?.isShowloading() else false } fun showloading(showText: String?) { if (activity != null && activity is BaseActivity) { (activity as BaseActivity?)?.showloading(showText) } } fun hideLoading() { if (activity != null && activity is BaseActivity) { (activity as BaseActivity?)?.hideLoading() } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/fragment/BasePluginResFragment.kt ================================================ package com.wgllss.core.fragment import android.content.Context import android.content.res.Resources import android.view.View import com.wgllss.core.units.ResourceUtils abstract class BasePluginResFragment(protected val packageName: String) : BaseFragment(0) { protected lateinit var resourcesPlugin: Resources override fun onAttach(context: Context) { super.onAttach(context) getPluginResources()?.let { resourcesPlugin = it } } override fun onStart() { super.onStart() onChangeSkin(getSkinResources()) } abstract fun getPluginResources(): Resources? abstract fun getSkinResources(): Resources fun findViewByID(contentView: View, IDResName: String): T = contentView.findViewById(ResourceUtils.getPluginID(resourcesPlugin, IDResName, packageName)) protected fun getPluginID(resName: String) = ResourceUtils.getPluginID(resourcesPlugin, resName, packageName) protected fun getSkinPluginID(resName: String) = ResourceUtils.getPluginID(getSkinResources(), resName, packageName) protected fun getPluginID(resources: Resources, resName: String) = ResourceUtils.getPluginID(resources, resName, packageName) open fun onChangeSkin(skinRes: Resources) { } open fun callChangeSkin(skinRes: Resources) { onChangeSkin(skinRes) childFragmentManager.fragments.forEach { if (it.isAdded && it is BasePluginResFragment) { it.callChangeSkin(skinRes) } } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/fragment/BaseViewModelClassFragment.kt ================================================ package com.wgllss.core.fragment import android.os.Bundle import androidx.activity.ComponentActivity import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import androidx.lifecycle.ViewModelProvider import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType open class BaseViewModelClassFragment(@LayoutRes private val contentLayoutId: Int) : BaseFragment(contentLayoutId) { protected lateinit var viewModel: VM override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) activity?.let { viewModel = lazyViewModels(it) initObserve() } } /** * activity 和 fragmnet 是否公用同一个viewModel */ protected open fun activitySameViewModel() = false @MainThread private fun lazyViewModels(activity: ComponentActivity): VM { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return if (activitySameViewModel()) { ViewModelProvider(activity.viewModelStore, activity.defaultViewModelProviderFactory).get(cls) } else { ViewModelProvider(viewModelStore, defaultViewModelProviderFactory).get(cls) } } /** * 监听当前ViewModel中 showDialog和error的值 */ protected open fun initObserve() { if (!activitySameViewModel()) viewModel?.run { showUIDialog.observe(viewLifecycleOwner, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(viewLifecycleOwner, Observer { onToast(it) }) } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/fragment/BaseViewModelFragment.kt ================================================ package com.wgllss.core.fragment import android.os.Bundle import androidx.activity.ComponentActivity import androidx.annotation.LayoutRes import androidx.annotation.MainThread import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType abstract class BaseViewModelFragment(packageName: String) : BasePluginResFragment(packageName) { protected lateinit var viewModel: VM override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) activity?.let { viewModel = lazyViewModels(it).value initObserve() } } /** * activity 和 fragmnet 是否公用同一个viewModel */ protected open fun activitySameViewModel() = false @MainThread private fun lazyViewModels(activity: ComponentActivity): Lazy { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return if (activitySameViewModel()) ViewModelLazy(cls.kotlin, { activity.viewModelStore }, { activity.defaultViewModelProviderFactory }) else ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) } /** * 监听当前ViewModel中 showDialog和error的值 */ protected open fun initObserve() { if (!activitySameViewModel()) viewModel?.run { showUIDialog.observe(viewLifecycleOwner, Observer { it -> if (it.isShow) showloading(it.msg) else hideLoading() }) errorMsgLiveData.observe(viewLifecycleOwner, Observer { onToast(it) }) } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/fragment/BaseViewModelPluginFragment.kt ================================================ package com.wgllss.core.fragment import android.content.Context import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.ComponentActivity import androidx.annotation.MainThread import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelLazy import com.wgllss.core.units.ResourceUtils import com.wgllss.core.viewmodel.BaseViewModel import java.lang.reflect.ParameterizedType abstract class BaseViewModelPluginFragment(private val layoutName: String, packageName: String) : BasePluginResFragment(packageName) { protected lateinit var containerView: View protected lateinit var viewModel: VM override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { if (!this::containerView.isInitialized) { resourcesPlugin.run { val layoutID = getIdentifier(layoutName, "layout", packageName) val xmlResourceParser = getLayout(layoutID) containerView = LayoutInflater.from(inflater.context).inflate(xmlResourceParser, container, false) findView(inflater.context, containerView) } } return containerView } open fun findView(context: Context, containerView: View) { } fun findViewByID(IDResName: String): T = containerView.findViewById(ResourceUtils.getPluginID(resourcesPlugin, IDResName, packageName)) override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) activity?.let { viewModel = lazyViewModels(it).value initObserve() } } /** * activity 和 fragmnet 是否公用同一个viewModel */ protected open fun activitySameViewModel() = false @MainThread private fun lazyViewModels(activity: ComponentActivity): Lazy { val cls = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class return if (activitySameViewModel()) ViewModelLazy(cls.kotlin, { activity.viewModelStore }, { activity.defaultViewModelProviderFactory }) else ViewModelLazy(cls.kotlin, { viewModelStore }, { defaultViewModelProviderFactory }) } /** * 监听当前ViewModel中 showDialog和error的值 */ protected open fun initObserve() { if (!activitySameViewModel()) viewModel?.run { showUIDialog.observe(viewLifecycleOwner) { if (it.isShow) showloading(it.msg) else hideLoading() } errorMsgLiveData.observe(viewLifecycleOwner) { onToast(it) } } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/http/HttpRequest.kt ================================================ package com.wgllss.core.http import java.net.HttpURLConnection import java.net.URL import java.security.SecureRandom import java.security.cert.CertificateException import java.security.cert.X509Certificate import javax.net.ssl.* object HttpRequest { fun getHttpURLConnection(url: URL, connectTimeOut: Int): HttpURLConnection? { return try { if ("https" == url.protocol) { trustAllHosts() (url.openConnection() as HttpsURLConnection).apply { HttpsURLConnection.setDefaultHostnameVerifier(hnv) hostnameVerifier = hnv HttpsURLConnection.setDefaultSSLSocketFactory(mSSLSocketFactory) sslSocketFactory = mSSLSocketFactory connectTimeout = 3 * connectTimeOut readTimeout = 3 * connectTimeOut } } else { (url.openConnection() as HttpURLConnection).apply { connectTimeout = connectTimeOut readTimeout = connectTimeOut } } } catch (e: Exception) { null } } /** * 信任所有host */ var hnv = HostnameVerifier { hostname, session -> true } /** * 设置https * * @author :Atar * @createTime:2015-9-17下午4:57:39 * @version:1.0.0 * @modifyTime: * @modifyAuthor: * @description: */ private fun trustAllHosts() { try { val trustAllCerts = arrayOf(object : X509TrustManager { override fun getAcceptedIssuers(): Array { return arrayOf() } @Throws(CertificateException::class) override fun checkClientTrusted(chain: Array, authType: String) { } @Throws(CertificateException::class) override fun checkServerTrusted(chain: Array, authType: String) { } }) val sc = SSLContext.getInstance("TLS") sc.init(null, trustAllCerts, SecureRandom()) if (mSSLSocketFactory == null) { mSSLSocketFactory = sc.socketFactory } HttpsURLConnection.setDefaultHostnameVerifier(hnv) HttpsURLConnection.setDefaultSSLSocketFactory(mSSLSocketFactory) } catch (e: Exception) { e.printStackTrace() } } var mSSLSocketFactory: SSLSocketFactory? = null /** * 设置请求头 * * @param httpConnection */ fun setConHead(httpConnection: HttpURLConnection) { httpConnection.apply { setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") setRequestProperty("Upgrade-Insecure-Requests", "1") setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Mobile Safari/537.36") setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3") // httpConnection.setRequestProperty("Accept-Encoding", "gzip, deflate, br") setRequestProperty("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7") setRequestProperty("Keep-Alive", "300") setRequestProperty("Connection", "keep-alive") setRequestProperty("Cache-Control", "max-age=0") } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/http/HttpUrlConnectionRequest.kt ================================================ package com.wgllss.core.http import java.io.BufferedReader import java.io.InputStreamReader import java.lang.StringBuilder import java.net.HttpURLConnection import java.net.URL object HttpUrlConnectionRequest { fun getServerJson(url: String): String { val result = StringBuilder() var httpConnection: HttpURLConnection? = null try { val url = URL(url) httpConnection = HttpRequest.getHttpURLConnection(url, 5000) HttpRequest.setConHead(httpConnection!!) httpConnection!!.connect() val responseCode = httpConnection!!.responseCode if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_PARTIAL) { val instream = httpConnection!!.inputStream if (instream != null) { val inputreader = InputStreamReader(instream) val buffreader = BufferedReader(inputreader) var line: String? // 分行读取 while (buffreader.readLine().also { line = it } != null) { result.append(line) } inputreader.close() instream.close() buffreader.close() } } } catch (e: Exception) { e.printStackTrace() } finally { httpConnection?.disconnect() // 关闭连接 } return result.toString() } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/material/ThemeUtils.kt ================================================ package com.wgllss.core.material // //import android.content.Context //import android.util.TypedValue // //object ThemeUtils { // // // @JvmStatic // fun getColorPrimary(context: Context): Int { // val typedValue = TypedValue() // context.theme.resolveAttribute(android.R.attr.colorPrimary, typedValue, true) // return typedValue.data // } // // @JvmStatic // fun getColorOnPrimary(context: Context): Int { // val typedValue = TypedValue() // context.theme.resolveAttribute(android.R.attr.textColorHighlight, typedValue, true) // return typedValue.data // } // // @JvmStatic // fun getTextColorPrimary(context: Context): Int { // val typedValue = TypedValue() // context.theme.resolveAttribute(android.R.attr.textColorPrimary, typedValue, true) // return typedValue.data // } // // @JvmStatic // fun getAndroidColorBackground(context: Context): Int { // val typedValue = TypedValue() // context.theme.resolveAttribute(android.R.attr.colorBackground, typedValue, true) // return typedValue.data // } //} ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/DeviceIdUtilX.kt ================================================ package com.wgllss.core.units import android.content.Context import android.os.Build import android.provider.Settings import java.security.MessageDigest import java.util.* /** * 1847470F0A12C2F310F7311FA719DBFE50510192 * 1847470F0A12C2F310F7311FA719DBFE50510192 * * 2F6039397BA7EEC402E7036339963B23810CCBFD */ object DeviceIdUtilX { private const val isDeviceSelfSerial = false private const val WD = "B03E4AFB9ADC842C9B3BDB6C57346ACEF6CE7504" private const val CD = "2F6039397BA7EEC402E7036339963B23810CCBFD" private const val ELSED = "dxde_m_p" fun getDeviceId(context: Context, needDevice: Boolean = false): String { if (isDeviceSelfSerial) { //todo 模拟序列号 return "2F6039397BA7EEC402E7036339963B23810CCBFD" // return getSerial(AppGlobals.sApplication) } else { // val context = AppGlobals.sApplication val sbDeviceId = StringBuilder() // val imei = getIMEI(context) val androidID = getAndroidId(context) // val serial = getSerial(context) val id = getDeviceUUID(context).replace("-", "") //追加imei // if (imei != null && imei.isNotEmpty()) { // sbDeviceId.append(imei) // sbDeviceId.append("|") // } //追加androidid if (androidID != null && androidID.isNotEmpty()) { sbDeviceId.append(androidID) sbDeviceId.append("|") } //追加serial // if (serial != null && serial.isNotEmpty()) { // sbDeviceId.append(serial) // sbDeviceId.append("|") // } //追加硬件uuid if (id != null && id.isNotEmpty()) { sbDeviceId.append(id) } if (sbDeviceId.toString().isNotEmpty()) { try { val hash = getHashByString(sbDeviceId.toString()) val sha1 = bytesToHex(hash!!) // LogTimer.LogE(this, sha1!!) if (sha1 != null && sha1.isNotEmpty()) { return if (needDevice || CD == sha1 || WD == sha1) sha1 else ELSED // return sha1 } } catch (ex: Exception) { ex.printStackTrace() } } val s = sbDeviceId.toString() return if (CD == s || WD == s) s else ELSED } } /** * 转16进制字符串 * * @param data 数据 * @return 16进制字符串 */ private fun bytesToHex(data: ByteArray): String? { val sb = StringBuilder() var stmp: String for (n in data.indices) { stmp = Integer.toHexString(data[n].toInt() and 0xFF) if (stmp.length == 1) sb.append("0") sb.append(stmp) } return sb.toString().uppercase(Locale.CHINA) } /** * 取SHA1 * * @param data 数据 * @return 对应的hash值 */ private fun getHashByString(data: String): ByteArray? { return try { val messageDigest: MessageDigest = MessageDigest.getInstance("SHA1") messageDigest.reset() messageDigest.update(data.toByteArray(charset("UTF-8"))) messageDigest.digest() } catch (e: java.lang.Exception) { " ".toByteArray() } } // //获得硬件uuid(根据硬件相关属性,生成uuid)(无需权限) 数字 0 -10 private fun getDeviceUUID(context: Context): String { val sb = StringBuilder().apply { append("100001") append(Build.BOARD) append(Build.BRAND) append(Build.DEVICE) append(Build.HARDWARE) append(Build.ID) append(Build.MODEL) append(Build.PRODUCT) // append(Build.SERIAL) } val long = sb.toString().hashCode().toLong() return UUID(long, long).toString() } // private fun getSerial(context: Context): String { // try { // if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // return Build.SERIAL // } else { // val permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) // if (permissionCheck == PackageManager.PERMISSION_GRANTED) { // return Build.getSerial() // } // } // } catch (ex: Exception) { // ex.printStackTrace() // } // return " " // } /** * 获得设备的AndroidId * * @param context 上下文 * @return 设备的AndroidId */ private fun getAndroidId(context: Context): String { try { return Settings.Secure.getString( context.contentResolver, Settings.Secure.ANDROID_ID ) } catch (ex: java.lang.Exception) { ex.printStackTrace() } return " " } // // //需要获得READ_PHONE_STATE权限,>=6.0,默认返回null // private fun getIMEI(context: Context): String { // try { // if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // val permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) // if (permissionCheck == PackageManager.PERMISSION_GRANTED) { // val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager // return tm.deviceId ?: " " // } // } // } catch (ex: Exception) { // ex.printStackTrace() // } // return " " // } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/ImageUtils.kt ================================================ package com.wgllss.core.units import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.drawable.Drawable object ImageUtils { fun drawableToBitmap(drawable: Drawable): Bitmap { val bitmap = Bitmap.createBitmap( drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 ) val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) return bitmap } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/ResourceUtils.kt ================================================ package com.wgllss.core.units import android.app.Activity import android.content.Context import android.content.res.ColorStateList import android.content.res.Resources import android.graphics.Color import android.graphics.drawable.Drawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText import android.widget.ImageView import android.widget.TextView import com.google.android.material.button.MaterialButton object ResourceUtils { fun setContentLayout(activity: Activity, resourcesPlugin: Resources, layoutName: String, packageNamePlugin: String) { val layoutID = resourcesPlugin.getIdentifier(layoutName, "layout", packageNamePlugin) val view = LayoutInflater.from(activity).inflate(resourcesPlugin.getLayout(layoutID), activity.window.decorView as ViewGroup, false) activity.setContentView(view) } fun getPluginView(context: Context, resourcesPlugin: Resources, resName: String, packageNamePlugin: String): View { val layoutID = resourcesPlugin.getIdentifier(resName, "layout", packageNamePlugin) return LayoutInflater.from(context).inflate(resourcesPlugin.getLayout(layoutID), null, false) } fun getPluginID(resourcesPlugin: Resources, resName: String, packageNamePlugin: String) = resourcesPlugin.getIdentifier(resName, "id", packageNamePlugin) fun getPluginDrawable(resourcesPlugin: Resources, resName: String, packageNamePlugin: String): Drawable = resourcesPlugin.getDrawable(resourcesPlugin.getIdentifier(resName, "drawable", packageNamePlugin)) fun getPluginColor(resourcesPlugin: Resources, resName: String, packageNamePlugin: String) = resourcesPlugin.getColor(resourcesPlugin.getIdentifier(resName, "color", packageNamePlugin)) fun getPluginDimen(resourcesPlugin: Resources, resName: String, packageNamePlugin: String) = resourcesPlugin.getDimension(resourcesPlugin.getIdentifier(resName, "dimen", packageNamePlugin)) fun getPluginString(resourcesPlugin: Resources, resName: String, packageNamePlugin: String) = resourcesPlugin.getString(resourcesPlugin.getIdentifier(resName, "string", packageNamePlugin)) fun getColorStatusList(resourcesPlugin: Resources, resName: String, packageNamePlugin: String) = resourcesPlugin.getColorStateList(resourcesPlugin.getIdentifier(resName, "drawable", packageNamePlugin)) fun setBackgroundColor(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: View) { view.forEach { it.setBackgroundColor(getPluginColor(resourcesPlugin, resName, packageNamePlugin)) } } fun setBackgroundDrawable(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: View) { view.forEach { it.setBackgroundDrawable(getPluginDrawable(resourcesPlugin, resName, packageNamePlugin)) } } fun setImageDrawable(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: ImageView) { view.forEach { it.setImageDrawable(getPluginDrawable(resourcesPlugin, resName, packageNamePlugin)) } } fun setTextColor(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: TextView) { view.forEach { it.setTextColor(getPluginColor(resourcesPlugin, resName, packageNamePlugin)) } } fun setTextColorHint(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: EditText) { view.forEach { it.setHintTextColor(getPluginColor(resourcesPlugin, resName, packageNamePlugin)) } } fun setText(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: TextView) { view.forEach { it.text = getPluginString(resourcesPlugin, resName, packageNamePlugin) } } fun setTextHint(resourcesPlugin: Resources, resName: String, packageNamePlugin: String, vararg view: TextView) { view.forEach { it.hint = getPluginString(resourcesPlugin, resName, packageNamePlugin) } } fun setMaterialButtonBackgroundHint(resourcesPlugin: Resources, resName1: String, resName2: String, packageNamePlugin: String, vararg view: MaterialButton) { val colors = intArrayOf(getPluginColor(resourcesPlugin, resName1, packageNamePlugin), getPluginColor(resourcesPlugin, resName2, packageNamePlugin)) val states = arrayOfNulls(2) states[0] = intArrayOf(android.R.attr.state_pressed) states[1] = intArrayOf(android.R.attr.state_enabled) view.forEach { it.backgroundTintList = ColorStateList(states, colors) } } fun setMaterialButtonBackgroundHint(colorStrPressed: String, colorStrEnable: String, vararg view: MaterialButton) { val colors = intArrayOf(Color.parseColor(colorStrPressed), Color.parseColor(colorStrEnable)) val states = arrayOfNulls(2) states[0] = intArrayOf(android.R.attr.state_pressed) states[1] = intArrayOf(android.R.attr.state_enabled) view.forEach { it.backgroundTintList = ColorStateList(states, colors) } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/ScreenManager.kt ================================================ package com.wgllss.core.units import android.content.Context import android.util.DisplayMetrics import android.view.View import android.view.WindowManager object ScreenManager { var screenWidth = 0 var screenHeight = 0 var widthSpec = 0 var heightSpec = 0 //初始化 屏幕 宽高相关属性 fun initScreenSize(context: Context) { val metric = DisplayMetrics() val manager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager manager.defaultDisplay.getRealMetrics(metric) screenWidth = metric.widthPixels screenHeight = metric.heightPixels widthSpec = View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.EXACTLY) heightSpec = View.MeasureSpec.makeMeasureSpec(screenHeight, View.MeasureSpec.EXACTLY) } fun measureAndLayout(view: View) { view?.measure(widthSpec, heightSpec) view?.layout(0, 0, screenWidth, screenHeight) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/SdkIntUtils.kt ================================================ package com.wgllss.core.units import android.os.Build object SdkIntUtils { fun isOreo(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O fun isMarshmallow() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M fun isLollipop() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP fun isJellyBeanMR2() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 fun isJellyBean() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN fun isJellyBeanMR1() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/ServiceUtil.kt ================================================ package com.wgllss.core.units // //import android.app.ActivityManager //import android.content.Context //import android.content.Intent //import android.os.Build //import androidx.annotation.RequiresApi // //object ServiceUtil { // // /** // * 判断某个服务是否存在 // * // * @param context // * @param className // * @return // */ // fun isServiceExisted(context: Context, className: String): Boolean { // val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager // val serviceList = activityManager.getRunningServices(Int.MAX_VALUE) // if (serviceList == null || serviceList.size <= 0) { // return false // } // for (i in serviceList.indices) { // val serviceInfo = serviceList[i] // val serviceName = serviceInfo.service // if (serviceName.className == className) { // return true // } // } // return false // } // // fun startService(packageContext: Context, cls: Class<*>) { // try { // if (!isServiceExisted(packageContext, cls.name)) { // val intent = Intent(packageContext, cls) // packageContext.startService(intent) // } // } catch (e: Exception) { // } // } // // @RequiresApi(Build.VERSION_CODES.O) // fun startForegroundService(packageContext: Context, cls: Class<*>) { // try { // if (!isServiceExisted(packageContext, cls.name)) { // val intent = Intent(packageContext, cls) // packageContext.startForegroundService(intent) // } // } catch (e: Exception) { // // } // } // // fun stopService(packageContext: Context, cls: Class<*>) { // try { // if (!isServiceExisted(packageContext, cls.name)) { // val intent = Intent(packageContext, cls) // packageContext.stopService(intent) // } // } catch (e: Exception) { // } // } //} ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/StatusBarUtil.kt ================================================ package com.wgllss.core.units import android.app.Activity import android.app.ActivityOptions import android.content.Context import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.os.Build import android.view.View import android.view.ViewGroup import android.view.Window import android.view.WindowManager import androidx.core.view.ViewCompat import com.wgllss.core.ex.getIntToDip import java.lang.reflect.Method import java.util.* /** * 屏幕相关工具类 * 1.设置沉浸式任务栏 * * @author LTP 16/9/21. */ object StatusBarUtil { /** * 模拟沉浸式状态栏,本质上是通过设置状态栏的颜色,可设置为与toolbar相同达到沉浸式的效果 * * @param activity 要设置的Activity */ // fun setImmersionStatus(activity: Activity) { // // 透明状态栏 // activity.window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) // activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) // activity.window.statusBarColor = activity.resources.getColor(R.color.purple_500) // } /** * 设置无状态栏,直接干掉顶部的状态栏,但要注意例如一些actionbar会自动顶到最上方需要适配 * * @param activity 要设置的Activity */ fun setNoStatus(activity: Activity) { // 透明状态栏 activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) } fun setStatusBarTranslucent(activity: Activity) { activity?.window?.apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { //适配刘海屏 val layoutParams = attributes layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; attributes = layoutParams } decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) statusBarColor = Color.TRANSPARENT } } /** * 设置状态栏 导航栏 透明 * * @param activity 需要设置的activity * @param color 状态栏颜色值 */ fun setNavigationBarStatusBarTranslucent(activity: Activity) { activity?.window?.apply { decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) navigationBarColor = Color.TRANSPARENT statusBarColor = Color.TRANSPARENT } } /** * 设置Android6.0上状态栏的字体颜色为黑色 * * @param activity Activity */ fun setStatusBarLightMode(activity: Activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR } } /** * 设置Android6.0上状态栏的字体颜色为黑色 * * @param activity Activity */ fun setStatusBarDarkMode(activity: Activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { activity.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN } } /** * 获取手机状态栏的高度 */ fun getStatusBarHeight(context: Context): Int { val resourceId = context.resources.getIdentifier("status_bar_height", "dimen", "android") return context.resources.getDimensionPixelSize(resourceId) } fun translucentStatusBar(activity: Activity, toolbar: ViewGroup? = null) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val window = activity.window window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) window.statusBarColor = Color.TRANSPARENT window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION val mContentView = window.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup val mChildView = mContentView.getChildAt(0) if (mChildView != null) { ViewCompat.setFitsSystemWindows(mChildView, false) ViewCompat.requestApplyInsets(mChildView) } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 透明状态栏 activity.window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && toolbar != null) { val statusBarHeight: Int = getStatusBarHeight(activity) val layoutHeight = (if (statusBarHeight > 0) statusBarHeight else 36) + activity.getIntToDip(42f) as Int val lp = toolbar.layoutParams lp.height = layoutHeight toolbar.setPadding(0, statusBarHeight, 0, 0) } } catch (e: Exception) { } } fun translucentActivity(activity: Activity) { try { activity.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) activity.window.decorView.background = null val activityOptions: Method = Activity::class.java.getDeclaredMethod("getActivityOptions") activityOptions.isAccessible = true val option = activityOptions.invoke(activity) val classes = Activity::class.java.declaredClasses var aClass: Class? = null classes.forEach { if (it.simpleName.contains("TranslucentConversionListener")) { aClass = it } } val method: Method = Activity::class.java.getDeclaredMethod("convertToTranslucent", aClass, ActivityOptions::class.java) method.isAccessible = true method.invoke(activity, null, option) } catch (e: Exception) { e.printStackTrace() } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/units/WLog.kt ================================================ package com.wgllss.core.units import com.wgllss.core.BuildConfig object WLog { fun e(any: Any, message: String) { if (BuildConfig.DEBUG) android.util.Log.e(any.javaClass.simpleName, message) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/viewmodel/BaseViewModel.kt ================================================ package com.wgllss.core.viewmodel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wgllss.core.data.DialogBean import com.wgllss.core.ex.flowOnIOAndCatch import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch abstract class BaseViewModel : ViewModel() { val ViewModel.errorMsgLiveData by lazy { MutableLiveData() } val ViewModel.showUIDialog by lazy { MutableLiveData() } fun ViewModel.show(strMessage: String = "正在请求数据") { val showBean = showUIDialog.value ?: DialogBean(strMessage, true) showBean.isShow = true showBean.msg = strMessage showUIDialog.postValue(showBean) } fun ViewModel.hide() { val showBean = showUIDialog.value ?: DialogBean("", true) showBean.isShow = false showUIDialog.postValue(showBean) } override fun onCleared() { viewModelScope.cancel() } abstract fun start() protected fun Flow.flowOnIOAndCatch(): Flow = flowOnIOAndCatch(errorMsgLiveData) protected fun Flow.onStartAndShow(strMessage: String = "正在请求数据"): Flow = onStart { show() } protected fun Flow.onCompletionAndHide(): Flow = onCompletion { hide() } protected suspend fun Flow.onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() { onStartAndShow().onCompletionAndHide().flowOnIOAndCatch().collect()//这里,开始结束全放在异步里面处理 } fun flowAsyncWorkOnViewModelScopeLaunch(flowAsyncWork: suspend () -> Flow) { viewModelScope.launch { flowAsyncWork.invoke().onStartShowAndFlowOnIOAndCatchAndOnCompletionAndHideAndCollect() } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/widget/ButtomNavigationViewEx.kt ================================================ package com.wgllss.core.widget import android.view.View import android.view.ViewGroup import com.google.android.material.bottomnavigation.BottomNavigationView /** * 处理BottomNavigationView中的tab长按出现toast的问题 * * @param ids tab项的id集 */ fun BottomNavigationView.clearLongClickToast(vararg ids: Int) { val bottomNavigationView: ViewGroup = getChildAt(0) as ViewGroup for (position in ids.indices) { bottomNavigationView.getChildAt(position).findViewById(ids[position]) .setOnLongClickListener { true } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/widget/DividerGridItemDecoration.kt ================================================ package com.wgllss.core.widget import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Rect import android.graphics.drawable.Drawable import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.StaggeredGridLayoutManager class DividerGridItemDecoration : RecyclerView.ItemDecoration { var ItemDecorationView //间隔视图 : View? = null var ItemDecorationViewDrawble //间隔视图的drawble : Drawable? = null var ItemDecorationViewWidth = 0 //间隔视图的宽度 var ItemDecorationViewHeight = 0 //间隔视图的高度 constructor(context: Context?, orientation: Int, ItemDecorationView: View?) { //判断传入的view以及传入的view的params是否为空,若其中一个为空则使用默认样式 var ItemDecorationView = ItemDecorationView if (ItemDecorationView == null || ItemDecorationView.layoutParams == null) { ItemDecorationView = ImageView(context) ItemDecorationView.setLayoutParams(ViewGroup.LayoutParams(5, 5)) ItemDecorationView.setBackgroundColor(Color.parseColor("#EEEEEE")) } this.ItemDecorationView = ItemDecorationView this.ItemDecorationView!!.measure(0, 0) this.ItemDecorationViewDrawble = ItemDecorationView.background if (this.ItemDecorationView!!.getMeasuredHeight() >= 0) { ItemDecorationViewHeight = this.ItemDecorationView!!.getMeasuredHeight() } if (this.ItemDecorationView!!.getMeasuredWidth() >= 0) { ItemDecorationViewWidth = this.ItemDecorationView!!.getMeasuredWidth() } if (ItemDecorationView.layoutParams.height >= 0) { ItemDecorationViewHeight = ItemDecorationView.layoutParams.height } if (ItemDecorationView.layoutParams.width >= 0) { ItemDecorationViewWidth = ItemDecorationView.layoutParams.width } } override fun onDraw(c: Canvas, parent: RecyclerView) { drawHorizontal(c, parent!!) drawVertical(c, parent) } open fun getSpanCount(parent: RecyclerView): Int { // 列数 var spanCount = 1 val layoutManager = parent.layoutManager if (layoutManager is GridLayoutManager) { spanCount = layoutManager.spanCount } else if (layoutManager is StaggeredGridLayoutManager) { spanCount = layoutManager .spanCount } return spanCount } open fun drawHorizontal(c: Canvas, parent: RecyclerView) { val childCount = parent.childCount for (i in 0 until childCount) { val child = parent.getChildAt(i) val params = child .layoutParams as RecyclerView.LayoutParams val left = child.left - params.leftMargin val right = (child.right + params.rightMargin + ItemDecorationViewWidth) val top = child.bottom + params.bottomMargin val bottom = top + ItemDecorationViewHeight ItemDecorationViewDrawble!!.setBounds(left, top, right, bottom) ItemDecorationViewDrawble!!.draw(c) } } open fun drawVertical(c: Canvas, parent: RecyclerView) { val childCount = parent.childCount val spanCount = getSpanCount(parent) for (i in 0 until childCount) { val child = parent.getChildAt(i) val params = child .layoutParams as RecyclerView.LayoutParams val top = child.top - params.topMargin val bottom = child.bottom + params.bottomMargin val left = child.right + params.rightMargin var right = left + ItemDecorationViewWidth if ((i + 1) % spanCount == 0) { //最后一列 right = left } ItemDecorationViewDrawble!!.setBounds(left, top, right, bottom) ItemDecorationViewDrawble!!.draw(c) } } open fun isLastColum( parent: RecyclerView, pos: Int, spanCount: Int, childCount: Int ): Boolean { var childCount = childCount parent.addOnItemTouchListener(object : OnRecyclerViewItemClickListener(parent) { override fun onItemClickListener(viewHolder: RecyclerView.ViewHolder?, position: Int){ super.onItemClickListener(viewHolder, position) } override fun onItemLongClickListener(viewHolder: RecyclerView.ViewHolder?, position: Int) { super.onItemLongClickListener(viewHolder, position) } }) val layoutManager = parent.layoutManager if (layoutManager is GridLayoutManager) { if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边 { return true } } else if (layoutManager is StaggeredGridLayoutManager) { val orientation = layoutManager .orientation if (orientation == StaggeredGridLayoutManager.VERTICAL) { if ((pos + 1) % spanCount == 0) // 如果是最后一列,则不需要绘制右边 { return true } } else { childCount = childCount - childCount % spanCount if (pos >= childCount) // 如果是最后一列,则不需要绘制右边 return true } } else if (layoutManager is LinearLayoutManager) { val orientation = layoutManager .orientation if (orientation == LinearLayoutManager.HORIZONTAL) { // 如果是最后一行,则不需要绘制底部 if (pos + 1 >= childCount) return true } } return false } open fun isLastRaw( parent: RecyclerView, pos: Int, spanCount: Int, childCount: Int ): Boolean { var childCount = childCount val layoutManager = parent.layoutManager if (layoutManager is GridLayoutManager) { childCount = childCount - childCount % spanCount if (pos >= childCount) // 如果是最后一行,则不需要绘制底部 return true } else if (layoutManager is StaggeredGridLayoutManager) { val orientation = layoutManager .orientation // StaggeredGridLayoutManager 且纵向滚动 if (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount // 如果是最后一行,则不需要绘制底部 if (pos >= childCount) return true } else // StaggeredGridLayoutManager 且横向滚动 { // 如果是最后一行,则不需要绘制底部 if ((pos + 1) % spanCount == 0) { return true } } } else if (layoutManager is LinearLayoutManager) { val orientation = layoutManager .orientation if (orientation == LinearLayoutManager.VERTICAL) { // 如果是最后一行,则不需要绘制底部 if (pos + 1 >= childCount) return true } else { return true } } return false } override fun getItemOffsets( outRect: Rect, itemPosition: Int, parent: RecyclerView ) { val spanCount = getSpanCount(parent) val childCount = parent.adapter!!.itemCount if (isLastRaw(parent, itemPosition, spanCount, childCount)) // 如果是最后一行,则不需要绘制底部 { outRect[0, 0, ItemDecorationViewWidth] = 0 // } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边 // { // outRect.set(0, 0, 0, ItemDecorationViewHeight); } else { outRect[0, 0, ItemDecorationViewWidth] = ItemDecorationViewHeight } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/widget/DrawerBack.kt ================================================ package com.wgllss.core.widget import android.R import android.annotation.SuppressLint import android.app.Activity import android.graphics.Canvas import android.graphics.Color import android.graphics.Rect import android.os.Handler import android.view.* import android.view.animation.Interpolator import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.ListView import android.widget.Scroller class DrawerBack(activity: Activity) : FrameLayout(activity) { companion object { private const val SLIDE_TARGET_CONTENT = 0 private const val SLIDE_TARGET_WINDOW = 1 private const val SCROLL_DURATION = 400 private const val TOUCH_TARGET_WIDTH_DIP = 30 private const val TOUCH_HANDLE_WIDTH_DIP = 1.33f // 屏幕左侧4分之3 } private var mAdded = false private var mDrawerEnabled = true private var mDrawerOpened = false private var mDrawerMoving = false private var mGestureStarted = false private var mDecorOffsetX = 0 private var mGestureStartX = 0 private var mGestureCurrentX = 0 private var mGestureStartY = 0 private var mGestureCurrentY = 0 private var mSlideTarget = 0 private var mTouchTargetWidth = 0 private var mScrollerHandler: Handler? = null private var mScroller: Scroller? = null private var mDecorView: ViewGroup? = null private var mContentTarget: ViewGroup? = null private var mContentTargetParent: ViewGroup? = null private var mWindowTarget: ViewGroup? = null private var mWindowTargetParent: ViewGroup? = null private var mDecorContent: ViewGroup? = null private var mDecorContentParent: ViewGroup? = null private var mDrawerContent: LinearLayout? = null private var mVelocityTracker: VelocityTracker? = null private var mOnOpenDrawerCompleteListener: OnOpenDrawerCompleteListener? = null private var mLastMotionX = 0f private var mLastMotionY = 0f private var qx = 0f private var qy = 0f init { val dm = activity.resources.displayMetrics mTouchTargetWidth = dm.widthPixels / TOUCH_TARGET_WIDTH_DIP mScrollerHandler = Handler() mScroller = Scroller(activity, SmoothInterpolator()) mSlideTarget = SLIDE_TARGET_WINDOW mDecorView = activity.window.decorView as ViewGroup mWindowTarget = mDecorView!!.getChildAt(0) as ViewGroup mWindowTargetParent = mWindowTarget!!.parent as ViewGroup mContentTarget = mDecorView!!.findViewById(R.id.content) as ViewGroup mContentTargetParent = mContentTarget!!.parent as ViewGroup mDrawerContent = LinearLayout(context) mDrawerContent!!.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT) mDrawerContent!!.setBackgroundColor(Color.TRANSPARENT) reconfigureViewHierarchy() mDrawerContent!!.setPadding(0, 0, mTouchTargetWidth, 0) } class SmoothInterpolator : Interpolator { override fun getInterpolation(v: Float): Float { return (Math.pow(v.toDouble() - 1.0, 5.0) + 1.0f).toFloat() } } private fun reconfigureViewHierarchy() { if (mDecorView == null) { return } if (mDrawerContent != null) { removeView(mDrawerContent) } if (mDecorContent != null) { removeView(mDecorContent) mDecorContentParent!!.addView(mDecorContent) mDecorContent!!.setOnClickListener(null) mDecorContent!!.setBackgroundColor(Color.TRANSPARENT) } if (mAdded) { mDecorContentParent!!.removeView(this) } if (mSlideTarget == SLIDE_TARGET_CONTENT) { mDecorContent = mContentTarget mDecorContentParent = mContentTargetParent } else if (mSlideTarget == SLIDE_TARGET_WINDOW) { mDecorContent = mWindowTarget mDecorContentParent = mWindowTargetParent } else { throw IllegalArgumentException("Slide target must be one of SLIDE_TARGET_CONTENT or SLIDE_TARGET_WINDOW.") } (mDecorContent!!.parent as ViewGroup).removeView(mDecorContent) addView(mDrawerContent) addView(mDecorContent, LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)) mDecorContentParent!!.addView(this) mAdded = true mDecorContent!!.setBackgroundColor(Color.TRANSPARENT) mDecorContent!!.setOnClickListener { } } @SuppressLint("DrawAllocation") override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { val windowRect = Rect() mDecorView!!.getWindowVisibleDisplayFrame(windowRect) if (mSlideTarget == SLIDE_TARGET_WINDOW) { mDrawerContent!!.layout(left, top + windowRect.top, right, bottom) } else { mDrawerContent!!.layout(left, mDecorContent!!.top, right, bottom) } mDecorContent!!.layout(mDecorContent!!.left, mDecorContent!!.top, mDecorContent!!.left + right, bottom) } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { val vc = ViewConfiguration.get(context) val widthPixels = resources.displayMetrics.widthPixels val touchThreshold = widthPixels / TOUCH_HANDLE_WIDTH_DIP val hypo: Double val overcameSlop: Boolean if (!mDrawerEnabled) { return false } val x = ev.x val y = ev.y when (ev.action) { MotionEvent.ACTION_DOWN -> { mLastMotionX = x mLastMotionY = y mGestureCurrentX = (ev.x + 0.5f).toInt() mGestureStartX = mGestureCurrentX mGestureCurrentY = (ev.y + 0.5f).toInt() mGestureStartY = mGestureCurrentY if (mGestureStartX < touchThreshold && !mDrawerOpened) { mGestureStarted = true } if (mGestureStartX > widthPixels - mTouchTargetWidth && mDrawerOpened) { mGestureStarted = true } return false } MotionEvent.ACTION_MOVE -> { val dx = x - mLastMotionX val dy = y - mLastMotionY val xDiff = Math.abs(dx) val yDiff = Math.abs(y - mLastMotionY) if (xDiff > vc.scaledTouchSlop && Math.abs(xDiff) > Math.abs(yDiff) && Math.abs(dy) < Math.abs(vc.scaledTouchSlop / 1)) { } else { return false } if (!mGestureStarted) { return false } if (!mDrawerOpened && (ev.x < mGestureCurrentX || ev.x < mGestureStartX)) { return false.also { mGestureStarted = it } } mGestureCurrentX = (ev.x + 0.5f).toInt() mGestureCurrentY = (ev.y + 0.5f).toInt() hypo = Math.hypot((mGestureCurrentX - mGestureStartX).toDouble(), (mGestureCurrentY - mGestureStartY).toDouble()) overcameSlop = hypo > vc.scaledTouchSlop return overcameSlop } MotionEvent.ACTION_UP -> { if (mGestureStartX > widthPixels - mTouchTargetWidth && mDrawerOpened) { closeDrawer() } mGestureStarted = false mGestureCurrentX = -1 mGestureStartX = mGestureCurrentX mGestureCurrentY = -1 mGestureStartY = mGestureCurrentY return false } } return false } @SuppressLint("Recycle") override fun onTouchEvent(event: MotionEvent): Boolean { val vc = ViewConfiguration.get(context) val widthPixels = resources.displayMetrics.widthPixels val deltaX = (event.x + 0.5f).toInt() - mGestureCurrentX val deltaY = (event.y + 0.5f).toInt() - mGestureCurrentY if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain() } mVelocityTracker!!.addMovement(event) mGestureCurrentX = (event.x + 0.5f).toInt() mGestureCurrentY = (event.y + 0.5f).toInt() when (event.action) { MotionEvent.ACTION_MOVE -> { mDrawerMoving = true if (mDecorOffsetX + deltaX > widthPixels - mTouchTargetWidth) { if (mDecorOffsetX != widthPixels - mTouchTargetWidth) { mDrawerOpened = true mDecorContent!!.offsetLeftAndRight(widthPixels - mTouchTargetWidth - mDecorOffsetX) mDecorOffsetX = widthPixels - mTouchTargetWidth invalidate() } } else if (mDecorOffsetX + deltaX < 0) { if (mDecorOffsetX != 0) { mDrawerOpened = false mDecorContent!!.offsetLeftAndRight(0 - mDecorContent!!.left) mDecorOffsetX = 0 invalidate() } } else { if (mOnOpenDrawerCompleteListener != null && mOnOpenDrawerCompleteListener!!.onMoveRight()) { } else { mDecorContent!!.offsetLeftAndRight(deltaX) mDecorOffsetX += deltaX invalidate() return false } } return true } MotionEvent.ACTION_UP -> { qx = mGestureCurrentX.toFloat() qy = mGestureCurrentY.toFloat() mGestureStarted = false mDrawerMoving = false mVelocityTracker!!.computeCurrentVelocity(1000) if (Math.abs(mVelocityTracker!!.xVelocity) > vc.scaledMinimumFlingVelocity) { if (mVelocityTracker!!.xVelocity > 0 && mDecorOffsetX > widthPixels / 5.0) { mDrawerOpened = false openDrawer() } else { mDrawerOpened = true closeDrawer() } } else { if (mDecorOffsetX > widthPixels / 5.0) { mDrawerOpened = false openDrawer() } else { mDrawerOpened = true closeDrawer() } } return true } } return false } override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) if (mDrawerOpened || mDrawerMoving) { canvas.save() canvas.translate(mDecorOffsetX.toFloat(), 0f) canvas.restore() } } fun setOnDrawerBackEnabled(enabled: Boolean) { mDrawerEnabled = enabled } fun isDrawerEnabled(): Boolean { return mDrawerEnabled } fun toggleDrawer(animate: Boolean) { if (!mDrawerOpened) { openDrawer(animate) } else { closeDrawer(animate) } } fun toggleDrawer() { toggleDrawer(true) } fun openDrawer(animate: Boolean) { if (mDrawerOpened || mDrawerMoving) { return } mDrawerMoving = true val widthPixels = resources.displayMetrics.widthPixels mScroller!!.startScroll(mDecorOffsetX, 0, widthPixels - mDecorOffsetX, 0, if (animate) SCROLL_DURATION else 0) mScrollerHandler!!.postDelayed(object : Runnable { override fun run() { val scrolling = mScroller!!.computeScrollOffset() mDecorContent!!.offsetLeftAndRight(mScroller!!.currX - mDecorOffsetX) mDecorOffsetX = mScroller!!.currX postInvalidate() if (!scrolling) { mDrawerMoving = false mDrawerOpened = true mScrollerHandler!!.post { enableDisableViewGroup(mDecorContent, false) mOnOpenDrawerCompleteListener?.onOpenDrawerComplete() } } else { mScrollerHandler!!.postDelayed(this, 16) } } }, 16) } fun openDrawer() { openDrawer(true) } fun closeDrawer(animate: Boolean) { if (!mDrawerOpened || mDrawerMoving) { return } mDrawerMoving = true val widthPixels = resources.displayMetrics.widthPixels mScroller!!.startScroll(mDecorOffsetX, 0, -mDecorOffsetX, 0, if (animate) SCROLL_DURATION else 0) mScrollerHandler!!.postDelayed(object : Runnable { override fun run() { val scrolling = mScroller!!.computeScrollOffset() mDecorContent!!.offsetLeftAndRight(mScroller!!.currX - mDecorOffsetX) mDecorOffsetX = mScroller!!.currX postInvalidate() if (!scrolling) { mDrawerMoving = false mDrawerOpened = false // if (mDrawerCallbacks != null) { // mScrollerHandler.post(new Runnable() { // @Override // public void run() { // enableDisableViewGroup(mDecorContent, true); // mDrawerCallbacks.onDrawerClosed(); // } // }); // } } else { mScrollerHandler!!.postDelayed(this, 16) } } }, 16) } fun closeDrawer() { closeDrawer(true) } fun isDrawerOpened(): Boolean { return mDrawerOpened } fun isDrawerMoving(): Boolean { return mDrawerMoving } fun setOnOpenDrawerCompleteListener(mOnOpenDrawerCompleteListener: OnOpenDrawerCompleteListener?) { this.mOnOpenDrawerCompleteListener = mOnOpenDrawerCompleteListener } fun getSlideTarget(): Int { return mSlideTarget } fun setSlideTarget(slideTarget: Int) { if (mSlideTarget != slideTarget) { mSlideTarget = slideTarget reconfigureViewHierarchy() } } fun enableDisableViewGroup(viewGroup: ViewGroup?, enabled: Boolean) { val childCount = viewGroup!!.childCount for (i in 0 until childCount) { val view = viewGroup.getChildAt(i) if (view.isFocusable) { view.isEnabled = enabled } if (view is ViewGroup) { enableDisableViewGroup(view, enabled) } else if (view is ListView) { if (view.isFocusable()) { view.setEnabled(enabled) } val listView = view val listChildCount = listView.childCount for (j in 0 until listChildCount) { if (view.isFocusable()) { listView.getChildAt(j).isEnabled = false } } } } } interface OnOpenDrawerCompleteListener { fun onOpenDrawerComplete() fun onMoveRight(): Boolean } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/widget/MusicVisualizerView.kt ================================================ package com.wgllss.core.widget import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.util.AttributeSet import android.util.TypedValue import android.view.View import java.util.* class MusicVisualizerView constructor(context: Context, attrs: AttributeSet) : View(context, attrs) { private var random = Random() private var paint = Paint() private val animateView: Runnable = object : Runnable { override fun run() { //run every 100 ms postDelayed(this, 120) invalidate() } } init { //start runnable removeCallbacks(animateView) post(animateView) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) //set paint style, Style.FILL will fill the color, Style.STROKE will stroke the color paint.style = Paint.Style.FILL canvas.drawRect(getDimensionInPixel(0).toFloat(), (height - (40 + random.nextInt((height / 1.5f).toInt() - 25))).toFloat(), getDimensionInPixel(7).toFloat(), (height - 15).toFloat(), paint) canvas.drawRect(getDimensionInPixel(10).toFloat(), (height - (40 + random.nextInt((height / 1.5f).toInt() - 25))).toFloat(), getDimensionInPixel(17).toFloat(), (height - 15).toFloat(), paint) canvas.drawRect(getDimensionInPixel(20).toFloat(), (height - (40 + random.nextInt((height / 1.5f).toInt() - 25))).toFloat(), getDimensionInPixel(27).toFloat(), (height - 15).toFloat(), paint) } fun setColor(color: Int) { paint.color = color invalidate() } //get all dimensions in dp so that views behaves properly on different screen resolutions private fun getDimensionInPixel(dp: Int): Int { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), resources.displayMetrics).toInt() } override fun onWindowVisibilityChanged(visibility: Int) { super.onWindowVisibilityChanged(visibility) if (visibility == VISIBLE) { removeCallbacks(animateView) post(animateView) } else if (visibility == GONE) { removeCallbacks(animateView) } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Common-Library/src/main/java/com/wgllss/core/widget/OnRecyclerViewItemClickListener.kt ================================================ package com.wgllss.core.widget import android.view.GestureDetector import android.view.MotionEvent import android.view.View import androidx.core.view.GestureDetectorCompat import androidx.recyclerview.widget.RecyclerView open class OnRecyclerViewItemClickListener constructor(val recyclerView: RecyclerView) : RecyclerView.OnItemTouchListener { private lateinit var gestureDetectorCompat: GestureDetectorCompat init { gestureDetectorCompat = GestureDetectorCompat(recyclerView.context, object : GestureDetector.SimpleOnGestureListener() { override fun onLongPress(e: MotionEvent) { trasfomerItemEvent(e, 1) } override fun onSingleTapUp(e: MotionEvent): Boolean { trasfomerItemEvent(e, 0) return true } }) } private fun trasfomerItemEvent(e: MotionEvent, type: Int) { recyclerView?.let { it.findChildViewUnder(e.x, e.y) }?.apply { val viewHolder = recyclerView.getChildViewHolder(this) val position = recyclerView.getChildPosition(this) if (type == 0) { onItemClickListener(this, position) } else { onItemLongClickListener(this, position) } } } open fun onItemClickListener(itemRootView: View, position: Int) {} open fun onItemLongClickListener(itemRootView: View, position: Int) {} open fun onItemClickListener(viewHolder: RecyclerView.ViewHolder?, position: Int) {} open fun onItemLongClickListener(viewHolder: RecyclerView.ViewHolder?, position: Int) {} override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { gestureDetectorCompat.onTouchEvent(e) return false } override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) { gestureDetectorCompat.onTouchEvent(e) } override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {} } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-all-app/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-all-app/build.gradle ================================================ plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.kotlin.kapt) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.version.json" defaultConfig { applicationId "com.wgllss.dynamic.version.json" minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } kapt { generateStubs = true } } dependencies { implementation project(path: ':wgllss-sample-create-version-config-annotations') kapt project(path: ':wgllss-sample-create-version-config-compiler') } def createVersionJson(assembleReleaseTask, buildType) { def inputFile = file("${getProject().getBuildDir()}/outputs/apk/vc") def outputFile = file("${rootProject.getBuildDir()}/vc") if (outputFile.exists()) { outputFile.delete() } def inputFileJar = file("${project(":wgllss-sample-loader-version").getBuildDir()}/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar") def outputSrcFile = file("${project(":wgllss-sample-create-version-config-compiler").projectDir}/libs/classes.jar") def assembleCopyJarToLibs = tasks.create("assembleCopyJarToLibs") { doLast { if (outputSrcFile.exists()) { outputSrcFile.delete() } copy { from(inputFileJar.getParent()) { include(inputFileJar.name) rename { outputSrcFile.name } } into(outputSrcFile.getParent()) } } }.dependsOn(":wgllss-sample-loader-version:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-loader-version:assembleRelease") return tasks.create("assembleCreateAllFile${buildType.capitalize()}") { doLast { copy { from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) } } }.dependsOn(assembleReleaseTask.name) .dependsOn(assembleCopyJarToLibs.name) .dependsOn(":Wgllss-Dynamic-Plugin-RunTime-Apk:assembleCopy") .dependsOn(":wgllss-sample-ui-other-lib:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-ui-other2-lib2:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-ui-other2:assembleCopy") .dependsOn(":wgllss-sample-ui-other:assembleCopy") .dependsOn(":wgllss-sample-ui-loading:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-ui-home:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-assets-source-apk:assembleCopy") .dependsOn(":wgllss-sample-skin-resource-apk:assembleCopy") .dependsOn(":Wgllss-Dynamic-Plugin-Manager:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-business-library:assembleDxCommandAndCopy") .dependsOn(":Wgllss-Dynamic-Plugin-Common-Library:assembleDxCommandAndCopy") } tasks.whenTaskAdded { task -> if (task.name == "assembleRelease") { createVersionJson(task, "Release") } // if (task.name == "cleanJson") { // createVersionJson(task, "Release") // } } task assemblecleanJson(type: Delete) { delete buildDir } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-all-app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-all-app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-all-app/src/main/java/com/wgllss/dynamic/version/json/Test.kt ================================================ package com.wgllss.dynamic.version.json import com.wgllss.annotations.CreateVersionConfig @CreateVersionConfig class Test { } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-annotations/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-annotations/build.gradle ================================================ plugins { alias(libs.plugins.java.library) alias(libs.plugins.java.kotlin) } java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } dependencies { implementation libs.kotlin.stdlib } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-annotations/src/main/java/com/wgllss/annotations/CreateVersionConfig.kt ================================================ package com.wgllss.annotations @Suppress("SupportAnnotationUsage") @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class CreateVersionConfig { } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-app/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-app/build.gradle ================================================ plugins { alias(libs.plugins.android.application) alias(libs.plugins.jetbrains.kotlin.android) alias(libs.plugins.kotlin.kapt) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.version.json" defaultConfig { applicationId "com.wgllss.dynamic.version.json" minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } kapt { generateStubs = true } } dependencies { implementation project(path: ':wgllss-sample-create-version-config-annotations') kapt project(path: ':wgllss-sample-create-version-config-compiler') } def createVersionJson(assembleReleaseTask, buildType) { def inputFile = file("${getProject().getBuildDir()}/outputs/apk/vc") def outputFile = file("${rootProject.getBuildDir()}/vc") if (outputFile.exists()) { outputFile.delete() } def inputFileJar = file("${project(":wgllss-sample-loader-version").getBuildDir()}/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar") def outputSrcFile = file("${project(":wgllss-sample-create-version-config-compiler").projectDir}/libs/classes.jar") def assembleCopyJarToLibs = tasks.create("assembleCopyJarToLibs") { doLast { if (outputSrcFile.exists()) { outputSrcFile.delete() } copy { from(inputFileJar.getParent()) { include(inputFileJar.name) rename { outputSrcFile.name } } into(outputSrcFile.getParent()) } } }.dependsOn(":wgllss-sample-loader-version:assembleDxCommandAndCopy") .dependsOn(":wgllss-sample-loader-version:assembleRelease") return tasks.create("assembleCreateVersion2File${buildType.capitalize()}") { doLast { copy { from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) } } }.dependsOn(assembleReleaseTask.name) .dependsOn(assembleCopyJarToLibs.name) } tasks.whenTaskAdded { task -> if (task.name == "assembleRelease") { createVersionJson(task, "Release") } // if (task.name == "cleanJson") { // createVersionJson(task, "Release") // } } task assemblecleanJson(type: Delete) { delete buildDir } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-app/src/main/java/com/wgllss/dynamic/version/json/Test.kt ================================================ package com.wgllss.dynamic.version.json import com.wgllss.annotations.CreateVersionConfig @CreateVersionConfig class Test { } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-compiler/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-compiler/build.gradle ================================================ plugins { alias(libs.plugins.java.library) alias(libs.plugins.java.kotlin) alias(libs.plugins.java) alias(libs.plugins.kotlin.kapt) } java { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation libs.protobuf implementation libs.auto.service kapt libs.auto.service compileOnly libs.kotlin.stdlib implementation libs.kotlinpoet implementation project(path: ':wgllss-sample-create-version-config-annotations') // implementation files("${project(":wgllss-sample-loader-version").getBuildDir()}/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar") // implementation project(path: ':Wgllss-Dynamic-Host-Constant-Lib') // implementation project(path: ':Wgllss-Dynamic-Host-Version-Lib') implementation project(path: ':Wgllss-Dynamic-Host-Version-Lib') // implementation 'io.github.wgllss:Wgllss-Dynamic-Host-Constant-Lib:1.0.0.6' // implementation 'io.github.wgllss:Wgllss-Dynamic-Host-Version-Lib:1.0.0.7' } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Generate/wgllss-sample-create-version-config-compiler/src/main/java/com/wgllss/compiler/AptCreateConfigProcessor.kt ================================================ package com.wgllss.compiler import com.google.auto.service.AutoService import com.wgllss.annotations.CreateVersionConfig import com.wgllss.dynamic.host.lib.protobuf.PluginMode import com.wgllss.loader.version.LoaderVersionImpl import java.io.File import java.io.FileOutputStream import java.io.IOException import javax.annotation.processing.* import javax.lang.model.SourceVersion import javax.lang.model.element.TypeElement import javax.lang.model.util.Elements import javax.tools.Diagnostic import javax.tools.FileObject import javax.tools.StandardLocation @AutoService(Processor::class) class AptCreateConfigProcessor : AbstractProcessor() { private val OUTPUT_FILE_NAME = "vc" private var mFiler: Filer? = null private var mElementUtils: Elements? = null override fun init(processingEnv: ProcessingEnvironment?) { super.init(processingEnv) mFiler = processingEnv?.filer mElementUtils = processingEnv?.elementUtils } //指定处理的版本 override fun getSupportedSourceVersion(): SourceVersion { return SourceVersion.latestSupported() } //给到需要处理的注解 override fun getSupportedAnnotationTypes(): MutableSet { val types: LinkedHashSet = LinkedHashSet() getSupportedAnnotations().forEach { clazz: Class -> types.add(clazz.canonicalName) } return types } private fun getSupportedAnnotations(): Set> { val annotations: LinkedHashSet> = LinkedHashSet() // 需要解析的自定义注解 annotations.add(CreateVersionConfig::class.java) return annotations } /** KotlinPoet 官方helloWorld示例: val greeterClass = ClassName("", "Greeter") val file = FileSpec.builder("", "HelloWorld") .addType(TypeSpec.classBuilder("Greeter") .primaryConstructor(FunSpec.constructorBuilder() .addParameter("name", String::class).build()) .addProperty(PropertySpec.builder("name", String::class) .initializer("name").build()) .addFunction(FunSpec.builder("greet") .addStatement("println(%P)", "Hello, \$name").build()) .build()) .addFunction(FunSpec.builder("main") .addParameter("args", String::class, VARARG) .addStatement("%T(args[0]).greet()", greeterClass).build()) .build() file.writeTo(System.out) —————————————————————————————————— class Greeter(val name: String) { fun greet() {println("""Hello, $name""")}} fun main(vararg args: String) {Greeter(args[0]).greet()} */ override fun process(annotations: MutableSet, roundEnvironment: RoundEnvironment): Boolean { var fos: FileOutputStream? = null try { //filer.createResource()意思是创建源文件 //我们可以指定为class文件输出的地方, //StandardLocation.CLASS_OUTPUT:java文件生成class文件的位置,/app/build/intermediates/javac/debug/classes/目录下 //StandardLocation.SOURCE_OUTPUT:java文件的位置,一般在/ppjoke/app/build/generated/source/apt/目录下 //StandardLocation.CLASS_PATH 和 StandardLocation.SOURCE_PATH用的不多,指的了这个参数,就要指定生成文件的pkg包名了 val resource: FileObject = mFiler!!.createResource(StandardLocation.CLASS_OUTPUT, "", OUTPUT_FILE_NAME) val resourcePath = resource.toUri().path //由于我们想要把json文件生成在app/src/main/assets/目录下,所以这里可以对字符串做一个截取, //以此便能准确获取项目在每个电脑上的 /app/src/main/assets/的路径 val appPath = resourcePath.substring(0, resourcePath.indexOf("app") + 4) val vcPath = appPath + "build/outputs/apk/" val file = File(vcPath) if (!file.exists()) { file.mkdirs() } //此处就是稳健的写入了 val outPutFile = File(file, OUTPUT_FILE_NAME) if (outPutFile.exists()) { outPutFile.delete() } outPutFile.createNewFile() val bytes = createConfig().toByteArray(); fos = FileOutputStream(outPutFile) fos.write(bytes) fos.flush() } catch (e: IOException) { e.printStackTrace() } finally { if (fos != null) { try { fos.close() } catch (e: IOException) { e.printStackTrace() } } } return true } private fun log(message: String) { processingEnv.messager.printMessage(Diagnostic.Kind.NOTE, message) } private fun createConfig(): PluginMode._PluginMode { val loader = LoaderVersionImpl() val pluginMode = PluginMode._PluginMode.newBuilder() .setV(loader.getV()) .setClfd(PluginMode._PluginMode._Plugin.newBuilder().setV(loader.getClfd().third).setDlu(loader.getClfd().second).setIsApkRes(false).build()) .setClmd(PluginMode._PluginMode._Plugin.newBuilder().setV(loader.getClmd().third).setDlu(loader.getClmd().second).setIsApkRes(false).build()) .setCdlfd(PluginMode._PluginMode._Plugin.newBuilder().setV(loader.getCdlfd().third).setDlu(loader.getCdlfd().second).setIsApkRes(false).build()) val map = linkedMapOf() loader.getMapDLU().forEach { (key, value) -> map[key] = PluginMode._PluginMode._Plugin.newBuilder().setV(value.second).setDlu(value.first).setIsApkRes(false).build() } pluginMode.putAllMapDl(map) loader.getOthers().forEach { (key, value) -> val isApkRes = key.contains("_res") pluginMode.addOthers(PluginMode._PluginMode._Plugin.newBuilder().setV(value).setDlu(key).setIsApkRes(isApkRes).build()) } return pluginMode.build() } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-DownloadFace-Impl/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-DownloadFace-Impl/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.plugin.download_face.impl" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { // compileOnly project(path: ':Wgllss-Dynamic-Host-Download-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Constant-Lib') compileOnly project(path: ':wgllss-common-re-library') compileOnly project(path: ':Wgllss-Dynamic-Host-Version-Lib') compileOnly project(path: ':Wgllss-Dynamic-Host-Lib') } def createCopyTask(buildType) { def workingDirPath = rootProject.ext.workingDirPath def outputFile = file("${workingDirPath}classes_downloadface_impl.jar") def outputDexFile = file("${workingDirPath}classes_downloadface_impl_dex.jar") def lastOutputDexFile = file("${rootProject.getBuildDir()}/classes_downloadface_impl_dex") if (lastOutputDexFile.exists()) { lastOutputDexFile.delete() } if (outputDexFile.exists()) { outputDexFile.delete() } if (outputFile.exists()) { outputFile.delete() } def inputFile = file("${getProject().getBuildDir()}/intermediates/aar_main_jar/${buildType}/sync${buildType}LibJars/classes.jar") def copyTask = tasks.create("assembleCopy${buildType.capitalize()}", Copy) { group = 'other' description = "复制${name}到dx环境中." from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn("assemble${buildType.capitalize()}") def assembleDxCommand = tasks.create("assembleDxCommand", Exec) { group = 'other' description = "${name}到dx执行中..." workingDir workingDirPath if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) { it.commandLine 'cmd', '/c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } else { it.commandLine 'bash', '-c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } // it.commandLine 'cmd', "/c", "d8 --output ${outputDexFile.name} ${outputFile.name}" }.dependsOn(copyTask.name) return tasks.create("assembleDxCommandAndCopy") { doLast { copy { from(outputDexFile.getParent()) { include(outputDexFile.name) rename { lastOutputDexFile.name } } into(lastOutputDexFile.getParent()) } } }.dependsOn(assembleDxCommand.name) } tasks.whenTaskAdded { task -> // if (task.name == "assembleDebug") { // createCopyTask("Debug") // } if (task.name == "assembleRelease") { createCopyTask("Release") } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-DownloadFace-Impl/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-DownloadFace-Impl/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-DownloadFace-Impl/src/main/java/com/wgllss/dynamic/plugin/download_face/DownLoadFaceImpl.kt ================================================ package com.wgllss.dynamic.plugin.download_face import android.text.TextUtils import com.wgllss.core.units.DeviceIdUtil import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.CDLFD import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.CLMD import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.COMMON import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.COMMON_BUSINESS import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.FIRST import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.HOME import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.MANAGER import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.RESOURCE_SKIN import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.RUNTIME import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.VERSION import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.WEB_ASSETS import com.wgllss.dynamic.host.lib.download.IDynamicDownLoadFace class DownLoadFaceImpl : IDynamicDownLoadFace { private var baseXL: String = "" // override fun getHostL() = "http://192.168.3.21:8080/assets/WXDynamicPlugin/" // override fun getHostL() = "http://192.168.1.9:8080/assets/WXDynamicPlugin/" override fun getHostL() = "https://gitee.com/wgllss888/WXDynamicPlugin/raw/master/WX-Resource/" /** 0:WXDynamicPlugin 动态化插件框架 理论上已经做到了可以完全不动宿主,但是如果一定要动宿主 可以提供以下思路: * 1:可以根据 宿主版本号得到 宿主版本支持的 的插件, * 2:当宿主必须 需要升级时,升级后原版本的插件不可用了,插件配置在新宿主版本文件夹下面,原宿主版本文件夹可可以先动态配置 在启动页 升级下载新的宿主 * @example 宿主版本 10000 版本支持的插件 放在服务端 WXDynamicPlugin/10000/ 文件夹下 20000版本的插件放在 WXDynamicPlugin/20000/下面 */ override fun getBaseL(): String { if (TextUtils.isEmpty(baseXL)) { baseXL = StringBuilder().append(getHostL()).append(DeviceIdUtil.getDeviceId()).append("/").append("10000").append("/").toString() } return baseXL } override fun isDebug() = true override fun getOtherDLU() = "${getBaseL()}vc" override fun getMapDLU() = mutableMapOf( VERSION to "${getBaseL()}classes_version_dex", COMMON to "${getBaseL()}classes_common_lib_dex", WEB_ASSETS to "${getBaseL()}classes_business_web_res", COMMON_BUSINESS to "${getBaseL()}classes_business_lib_dex", HOME to "${getBaseL()}classes_home_dex", RESOURCE_SKIN to "${getBaseL()}classes_common_skin_res", RUNTIME to "${getBaseL()}classes_wgllss_dynamic_plugin_runtime", MANAGER to "${getBaseL()}classes_manager_dex", FIRST to "${getBaseL()}classes_loading_dex", CLMD to "${getBaseL()}class_loader_impl_dex", CDLFD to "${getBaseL()}classes_downloadface_impl_dex" ) override fun getLoadVersionClassName() = "com.wgllss.loader.version.LoaderVersionImpl" } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Loader-Impl/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Loader-Impl/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.plugin.loader.impl" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { // compileOnly project(path: ':Wgllss-Dynamic-Host-Loader-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Loader-Base-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Download-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Version-Lib') compileOnly project(path: ':Wgllss-Dynamic-Host-Lib') } def createCopyTask(buildType) { def workingDirPath = rootProject.ext.workingDirPath def outputFile = file("${workingDirPath}class_loader_impl.jar") def outputDexFile = file("${workingDirPath}class_loader_impl_dex.jar") def lastOutputDexFile = file("${rootProject.getBuildDir()}/class_loader_impl_dex") if (lastOutputDexFile.exists()) { lastOutputDexFile.delete() } if (outputDexFile.exists()) { outputDexFile.delete() } if (outputFile.exists()) { outputFile.delete() } def inputFile = file("${getProject().getBuildDir()}/intermediates/aar_main_jar/${buildType}/sync${buildType}LibJars/classes.jar") def copyTask = tasks.create("assembleCopy${buildType.capitalize()}", Copy) { group = 'other' description = "复制${name}到dx环境中." from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn("assemble${buildType.capitalize()}") def assembleDxCommand = tasks.create("assembleDxCommand", Exec) { group = 'other' description = "${name}到dx执行中..." workingDir workingDirPath if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) { it.commandLine 'cmd', '/c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } else { it.commandLine 'bash', '-c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } // it.commandLine 'cmd', "/c", "d8 --output ${outputDexFile.name} ${outputFile.name}" }.dependsOn(copyTask.name) return tasks.create("assembleDxCommandAndCopy") { doLast { copy { from(outputDexFile.getParent()) { include(outputDexFile.name) rename { lastOutputDexFile.name } } into(lastOutputDexFile.getParent()) } } }.dependsOn(assembleDxCommand.name) } tasks.whenTaskAdded { task -> // if (task.name == "assembleDebug") { // createCopyTask("Debug") // } if (task.name == "assembleRelease") { createCopyTask("Release") } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Loader-Impl/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Loader-Impl/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Loader-Impl/src/main/java/com/wgllss/dynamic/plugin/loader/LoaderManagerImpl.kt ================================================ package com.wgllss.dynamic.plugin.loader import android.content.Context import com.wgllss.dynamic.host.lib.download.IDynamicDownLoadFace import com.wgllss.dynamic.host.lib.loader_base.BaseLoaderManagerImpl class LoaderManagerImpl : BaseLoaderManagerImpl() { override fun initDynamicLoader( context: Context, v: Int, clfd: Triple, clmd: Triple, cdlfd: Triple, mapDlu: MutableMap>, cotd: MutableMap, faceImpl: IDynamicDownLoadFace, isMustShowLoading: Boolean ) { android.util.Log.e("LoaderManagerImpl", "-----initDynamicLoader-----") super.initDynamicLoader(context, v, clfd, clmd, cdlfd, mapDlu, cotd, faceImpl, isMustShowLoading) } // override fun initDynamicRunTime(context: Context, contentKey: String, fileAbsolutePath: String) { // super.initDynamicRunTime(context, contentKey, fileAbsolutePath) // } // // override fun initHomeCreate(context: Context, classLoader: ClassLoader) { // super.initHomeCreate(context, classLoader) // } // private fun test() { this.v this.clfd this.clmd this.cdlfd this.mapDlu this.cotd this.faceImpl this.mapOthers this.isShowLoadFlag this.libIsLoadComplete this.firstLoadSuccess this.hasOldFileDelete this.libLoadCount } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/build.gradle ================================================ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.plugin.manager" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } dependencies { compileOnly libs.androidx.core.ktx compileOnly libs.appcompat compileOnly libs.androidx.activity compileOnly project(path: ':Wgllss-Dynamic-Plugin-Common-Library') compileOnly project(path: ':Wgllss-Dynamic-Plugin-Library') compileOnly project(path: ':wgllss-sample-business-library') // compileOnly project(path: ':Wgllss-Dynamic-Host-Constant-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Lib-Impl') // compileOnly project(path: ':Wgllss-Dynamic-Host-Loader-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Loader-Base-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-ClassLoader-Lib') // compileOnly project(path: ':Wgllss-Dynamic-Host-Download-Lib') compileOnly project(path: ':Wgllss-Dynamic-Host-Version-Lib') compileOnly project(path: ':Wgllss-Dynamic-Host-Lib') } def createCopyTask(buildType) { def workingDirPath = rootProject.ext.workingDirPath def outputFile = file("${workingDirPath}classes_manager.jar") def outputDexFile = file("${workingDirPath}classes_manager_dex.jar") def lastOutputDexFile = file("${rootProject.getBuildDir()}/classes_manager_dex") if (lastOutputDexFile.exists()) { lastOutputDexFile.delete() } if (outputDexFile.exists()) { outputDexFile.delete() } if (outputFile.exists()) { outputFile.delete() } def inputFile = file("${getProject().getBuildDir()}/intermediates/aar_main_jar/${buildType}/sync${buildType}LibJars/classes.jar") def copyTask = tasks.create("assembleCopy${buildType.capitalize()}", Copy) { group = 'other' description = "复制${name}到dx环境中." from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn("assemble${buildType.capitalize()}") def assembleDxCommand = tasks.create("assembleDxCommand", Exec) { group = 'other' description = "${name}到dx执行中..." workingDir workingDirPath if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) { it.commandLine 'cmd', '/c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } else { it.commandLine 'bash', '-c', "d8 --release --output ${outputDexFile.name} ${outputFile.name}" } // it.commandLine 'cmd', "/c", "d8 --output ${outputDexFile.name} ${outputFile.name}" }.dependsOn(copyTask.name) return tasks.create("assembleDxCommandAndCopy") { doLast { copy { from(outputDexFile.getParent()) { include(outputDexFile.name) rename { lastOutputDexFile.name } } into(lastOutputDexFile.getParent()) } } }.dependsOn(assembleDxCommand.name) } tasks.whenTaskAdded { task -> // if (task.name == "assembleDebug") { // createCopyTask("Debug") // } if (task.name == "assembleRelease") { createCopyTask("Release") } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/src/main/java/com/wgllss/dynamic/plugin/manager/PluginManager.kt ================================================ package com.wgllss.dynamic.plugin.manager import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.content.pm.PackageManager import android.content.res.Resources import android.os.IBinder import android.text.TextUtils import com.wgllss.core.activity.BaseViewPluginResActivity import com.wgllss.core.activity.WActivityManager import com.wgllss.core.units.WLog import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.RESOURCE_SKIN import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.WEB_ASSETS import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.dldir import com.wgllss.dynamic.host.lib.constant.DynamicPluginConstant.versionFile import com.wgllss.dynamic.host.lib.download.DynamicDownloadPlugin import com.wgllss.dynamic.host.lib.download.IDynamicDownLoadFace import com.wgllss.dynamic.host.lib.impl.WXDynamicLoader import com.wgllss.dynamic.host.lib.loader_base.DynamicManageUtils import com.wgllss.dynamic.host.lib.loader_base.DynamicManageUtils.getDlfn import com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface import com.wgllss.sample.feature_system.savestatus.MMKVHelp import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.zip import kotlinx.coroutines.runBlocking import java.io.File import java.util.concurrent.ConcurrentHashMap class PluginManager private constructor() { /** res apk*/ private val resFileName by lazy { WXDynamicLoader.instance.loader.getMapDluImpl()[RESOURCE_SKIN]!!.run { getDlfn(first, second) } } private val webResFileName by lazy { WXDynamicLoader.instance.loader.getMapDluImpl()[WEB_ASSETS]!!.run { getDlfn(first, second) } } /** 加载插件管理器 dex **/ private val clmd by lazy { WXDynamicLoader.instance.loader.getClmdImpl() } /** 下载接口实现 dex **/ private val cdlfd by lazy { WXDynamicLoader.instance.loader.getCdlfdImpl() } /**others dex*/ private val cotd by lazy { WXDynamicLoader.instance.loader.getCotdImpl() } private val mapOtherLoadStatus by lazy { WXDynamicLoader.instance.loader.getOtherLoadStatus() } private val context by lazy { WXDynamicLoader.instance.context } private val skinMap by lazy { ConcurrentHashMap() } private val mapAidl by lazy { HashMap() } private val mapConnection by lazy { HashMap() } private val mapContextPluginService by lazy { HashMap>() } companion object { const val pluginApkPathKey = "PLUGIN_APK_PATH_KEY" const val activityNameKey = "ACTIVITY_NAME_KEY" const val serviceNameKey = "PLUGIN_SERVICE_NAME_KEY" const val privatePackageKey = "PRIVATE_PACKAGE_KEY" private const val PluginStandardActivity = "com.wgllss.dynamic.plugin.runtime.PluginStandardActivity" private const val PluginSingleInstanceActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleInstanceActivity" private const val PluginSingleTaskActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleTaskActivity" private const val PluginSingleTopActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleTopActivity" private const val PluginStandardComposeActivity = "com.wgllss.dynamic.plugin.runtime.PluginStandardComposeActivity" private const val PluginSingleInstanceComposeActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleInstanceComposeActivity" private const val PluginSingleTaskComposeActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleTaskComposeActivity" private const val PluginSingleTopComposeActivity = "com.wgllss.dynamic.plugin.runtime.PluginSingleTopComposeActivity" private const val PluginStartStickyService = "com.wgllss.dynamic.plugin.runtime.PluginStartStickyService" private const val PluginStartNotStickyService = "com.wgllss.dynamic.plugin.runtime.PluginStartNotStickyService" private const val PluginStartRedeliverIntentService = "com.wgllss.dynamic.plugin.runtime.PluginStartRedeliverIntentService" private const val PluginStartStickyCompatibilityService = "com.wgllss.dynamic.plugin.runtime.PluginStartStickyCompatibilityService" private const val PluginProcessStartStickyService = "com.wgllss.dynamic.plugin.runtime.PluginProcessStartStickyService" private const val PluginProcessStartNotStickyService = "com.wgllss.dynamic.plugin.runtime.PluginProcessStartNotStickyService" private const val PluginProcessStartRedeliverIntentService = "com.wgllss.dynamic.plugin.runtime.PluginProcessStartRedeliverIntentService" private const val PluginProcessStartStickyCompatibilityService = "com.wgllss.dynamic.plugin.runtime.PluginProcessStartStickyCompatibilityService" val instance by lazy { PluginManager() } } fun switchSkinResources(skinPath: String) { val file = File(skinPath) if (file.exists()) { val key = file.absolutePath if (!skinMap.containsKey(key)) { val res = getResourcesForApplication(file) skinMap[key] = res } MMKVHelp.saveSkinPath(key) } } fun callAllActivity(skinRes: Resources) { WActivityManager.getActivitys { if (it is BaseViewPluginResActivity) { it.callChangeSkin(skinRes) } } } fun getCurrentSkinPath() = MMKVHelp.getSkinPath() ?: getDefaultSkinPath() fun getPluginSkinResources(): Resources { val skinPath = MMKVHelp.getSkinPath() var file: File if (!TextUtils.isEmpty(skinPath)) { file = File(skinPath) if (!file.exists()) { file = File(getDefaultSkinPath()) } } else { file = File(getDefaultSkinPath()) } val key = file.absolutePath return if (skinMap.containsKey(key)) { skinMap[key]!! } else { android.util.Log.e("PluginManager", "PluginManager :${file.absolutePath}") val res = getResourcesForApplication(file) skinMap[key] = res MMKVHelp.saveSkinPath(key) res } } fun getPluginResources(contentKey: String): Resources { return getResourcesForApplication(DynamicManageUtils.getDxFile(context, dldir, getDlfn(contentKey, cotd[contentKey]!!))) } private fun getDefaultSkinPath() = StringBuilder(context.filesDir.absolutePath).apply { append(File.separator) append(dldir) append(File.separator) append(resFileName) }.toString() /** * web res 资源 */ fun getWebRes(): Resources { val file = DynamicManageUtils.getDxFile(context, dldir, webResFileName) val flags = (PackageManager.GET_META_DATA or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_PROVIDERS or PackageManager.GET_RECEIVERS) val packageManager = context.applicationContext.packageManager val packageInfo = packageManager.getPackageArchiveInfo(file.absolutePath, flags) val applicationInfo = packageInfo!!.applicationInfo applicationInfo.publicSourceDir = file.absolutePath applicationInfo.sourceDir = applicationInfo.publicSourceDir MMKVHelp.saveWebResPath(file.absolutePath) return packageManager.getResourcesForApplication(applicationInfo) } private fun getResourcesForApplication(file: File): Resources { val flags = (PackageManager.GET_META_DATA or PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or PackageManager.GET_PROVIDERS or PackageManager.GET_RECEIVERS) val packageManager = context.applicationContext.packageManager val packageInfo = packageManager.getPackageArchiveInfo(file.absolutePath, flags) val applicationInfo = packageInfo!!.applicationInfo applicationInfo.publicSourceDir = file.absolutePath applicationInfo.sourceDir = applicationInfo.publicSourceDir return packageManager.getResourcesForApplication(applicationInfo) } fun startStandardActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginStandardActivity, activityName, packageName, intentOption) } fun startPluginSingleInstanceActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleInstanceActivity, activityName, packageName, intentOption) } fun startPluginSingleTaskActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleTaskActivity, activityName, packageName, intentOption) } fun startPluginSingleTopActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleTopActivity, activityName, packageName, intentOption) } fun startPluginStandardComposeActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginStandardComposeActivity, activityName, packageName, intentOption) } fun startPluginSingleInstanceComposeActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleInstanceComposeActivity, activityName, packageName, intentOption) } fun startPluginSingleTaskComposeActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleTaskComposeActivity, activityName, packageName, intentOption) } fun startPluginSingleTopComposeActivity(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null) { startActivity(context, contentKey, PluginSingleTopComposeActivity, activityName, packageName, intentOption) } private fun startActivity(context: Context, contentKey: String, lunchName: String, activityName: String, packageName: String, intentOption: Intent? = null) { try { if (!cotd.containsKey(contentKey)) return val clazz = Class.forName(lunchName) val intent = intentOption ?: Intent(context, clazz) if (intentOption != null) { intent.setClass(context, clazz) } intent.apply { putExtra(activityNameKey, activityName) putExtra(privatePackageKey, packageName) val file = DynamicManageUtils.getDxFile(context, dldir, getDlfn(contentKey, cotd[contentKey]!!)) if (!file.exists()) { return } putExtra(pluginApkPathKey, file.absolutePath) } context.startActivity(intent) } catch (e: Exception) { e.printStackTrace() } } fun getStandardActivityIntent(context: Context, contentKey: String, activityName: String, packageName: String, intentOption: Intent? = null): Intent? { return getActivityIntent(context, contentKey, PluginStandardActivity, activityName, packageName, intentOption) } private fun getActivityIntent(context: Context, contentKey: String, lunchName: String, activityName: String, packageName: String, intentOption: Intent? = null): Intent? { if (!cotd.containsKey(contentKey)) return null val clazz = Class.forName(lunchName) val intent = intentOption ?: Intent(context, clazz) if (intentOption != null) { intent.setClass(context, clazz) } intent.apply { putExtra(activityNameKey, activityName) putExtra(privatePackageKey, packageName) val file = DynamicManageUtils.getDxFile(context, dldir, getDlfn(contentKey, cotd[contentKey]!!)) if (!file.exists()) { return null } putExtra(pluginApkPathKey, file.absolutePath) } return intent } fun startPluginStartStickyService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginStartStickyService, pluginServiceName, packageName, intentOption) } fun startPluginStartNotStickyService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginStartNotStickyService, pluginServiceName, packageName, intentOption) } fun startPluginStartRedeliverIntentService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginStartRedeliverIntentService, pluginServiceName, packageName, intentOption) } fun startPluginStickyCompatibilityService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginStartStickyCompatibilityService, pluginServiceName, packageName, intentOption) } fun startPluginProcessStartStickyService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginProcessStartStickyService, pluginServiceName, packageName, intentOption) } fun startPluginProcessStartNotStickyService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginProcessStartNotStickyService, pluginServiceName, packageName, intentOption) } fun startPluginProcessStartRedeliverIntentService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginProcessStartRedeliverIntentService, pluginServiceName, packageName, intentOption) } fun startPluginProcessStickyCompatibilityService(context: Context, contentKey: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { startPluginService(context, contentKey, PluginProcessStartStickyCompatibilityService, pluginServiceName, packageName, intentOption) } private fun getServiceIntent(context: Context, contentKey: String, lunchName: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null): Intent? { if (!cotd.containsKey(contentKey)) return null val clazz = Class.forName(lunchName) val intent = intentOption ?: Intent(context, clazz) if (intentOption != null) { intent.setClass(context, clazz) } intent.apply { putExtra(serviceNameKey, pluginServiceName) putExtra(privatePackageKey, packageName) val file = DynamicManageUtils.getDxFile(context, dldir, getDlfn(contentKey, cotd[contentKey]!!)) if (!file.exists()) { return null } putExtra(pluginApkPathKey, file.absolutePath) } return intent } private fun startPluginService(context: Context, contentKey: String, lunchName: String, pluginServiceName: String, packageName: String, intentOption: Intent? = null) { try { getServiceIntent(context, contentKey, lunchName, pluginServiceName, packageName, intentOption)?.run { context.startService(this) } } catch (e: Exception) { e.printStackTrace() } } fun bindStickyService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginStartStickyService, contentKey, packageName, pluginServiceName, intentOption) } fun bindNotStickyService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginStartNotStickyService, contentKey, packageName, pluginServiceName, intentOption) } fun bindRedeliverService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginStartRedeliverIntentService, contentKey, packageName, pluginServiceName, intentOption) } fun bindCompatibilityService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginStartStickyCompatibilityService, contentKey, packageName, pluginServiceName, intentOption) } fun bindProcessStickyService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginProcessStartStickyService, contentKey, packageName, pluginServiceName, intentOption) } fun bindProcessNotStickyService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginProcessStartNotStickyService, contentKey, packageName, pluginServiceName, intentOption) } fun bindProcessRedeliverService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginProcessStartRedeliverIntentService, contentKey, packageName, pluginServiceName, intentOption) } fun bindProcessCompatibilityService(context: Context, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { bindService(context, PluginProcessStartStickyCompatibilityService, contentKey, packageName, pluginServiceName, intentOption) } private fun bindService(context: Context, hostServiceName: String, contentKey: String, packageName: String, pluginServiceName: String, intentOption: Intent? = null) { android.util.Log.e("bindService", "context:${context.javaClass.name}") val connectionKey = StringBuilder(hostServiceName).append(context.javaClass.name).toString() if (!mapAidl.containsKey(hostServiceName)) { // val intent = getServiceIntent(context, contentKey, hostServiceName, pluginServiceName, packageName, intentOption)?.let { val connection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { val aidl = WXDynamicAidlInterface.Stub.asInterface(service) mapAidl[hostServiceName] = aidl } override fun onServiceDisconnected(name: ComponentName?) { } } context.bindService(it, connection, Context.BIND_AUTO_CREATE) if (!mapConnection.containsKey(connectionKey)) { mapConnection[connectionKey] = connection } if (!mapContextPluginService.containsKey(connectionKey)) { mapContextPluginService[connectionKey] = mutableListOf(pluginServiceName) } } } else { val file = DynamicManageUtils.getDxFile(context, dldir, getDlfn(contentKey, cotd[contentKey]!!)) if (!file.exists()) { return } mapAidl[hostServiceName]?.onBind(pluginServiceName, packageName, file.absolutePath) if (!mapContextPluginService.containsKey(connectionKey)) { mapContextPluginService[connectionKey] = mutableListOf(pluginServiceName) } else { mapContextPluginService[connectionKey]?.add(pluginServiceName) } } } fun unBindStickyService(context: Context) { unBindService(context, PluginStartStickyService) } fun unBindNotStickyService(context: Context) { unBindService(context, PluginStartNotStickyService) } fun unBindRedeliverService(context: Context) { unBindService(context, PluginStartRedeliverIntentService) } fun unBindCompatibilityService(context: Context) { unBindService(context, PluginStartStickyCompatibilityService) } fun unBindProcessStickyService(context: Context) { unBindService(context, PluginProcessStartStickyService) } fun unBindProcessNotStickyService(context: Context) { unBindService(context, PluginProcessStartNotStickyService) } fun unBindProcessRedeliverService(context: Context) { unBindService(context, PluginProcessStartRedeliverIntentService) } fun unBindProcessCompatibilityService(context: Context) { unBindService(context, PluginProcessStartStickyCompatibilityService) } private fun unBindService(context: Context, hostServiceName: String) { val connectionKey = StringBuilder(hostServiceName).append(context.javaClass.name).toString() if (mapContextPluginService.containsKey(connectionKey)) { mapContextPluginService[connectionKey]?.forEach { v -> if (mapAidl.containsKey(hostServiceName)) { mapAidl[hostServiceName]?.onUnbind(v) mapAidl.remove(hostServiceName) } } mapContextPluginService.remove(connectionKey) } if (mapConnection.containsKey(connectionKey)) { context.unbindService(mapConnection[connectionKey]!!) mapConnection.remove(connectionKey) } } fun onAidlStickyServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginStartStickyService, PluginSerViceName, methodID) fun onAidlNotStickyServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginStartNotStickyService, PluginSerViceName, methodID) fun onAidlRedeliverServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginStartRedeliverIntentService, PluginSerViceName, methodID) fun onAidlCompatibilityServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginStartStickyCompatibilityService, PluginSerViceName, methodID) fun onProcessAidlStickyServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginProcessStartStickyService, PluginSerViceName, methodID) fun onProcessAidlNotStickyServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginProcessStartNotStickyService, PluginSerViceName, methodID) fun onProcessAidlRedeliverServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginProcessStartRedeliverIntentService, PluginSerViceName, methodID) fun onProcessAidlCompatibilityServiceCallBack(PluginSerViceName: String, methodID: Int) = onAidlCallBack(PluginProcessStartStickyCompatibilityService, PluginSerViceName, methodID) private fun onAidlCallBack(serviceName: String, PluginSerViceName: String, methodID: Int): String { if (mapAidl.containsKey(serviceName)) { mapAidl[serviceName]?.let { return it.onAidlCallBack(PluginSerViceName, methodID) } } return "" } fun deleteOldFile() { WXDynamicLoader.instance.loader.run { if (hasOldFileNeedDelete()) { val sbdex = StringBuilder(context.filesDir.absolutePath).apply { append(File.separator) append(dldir) append(File.separator) } val fileDexDir = File(sbdex.toString()) if (!fileDexDir.exists()) return@run val oatDir = "oat" sbdex.append(oatDir) val fileDexOatDir = File(sbdex.toString()) val list = mutableListOf() getMapDluImpl().forEach { list.add(it.value.run { getDlfn(first, second) }) } cotd.forEach { list.add(it.run { getDlfn(key, value) }) } list.add(clmd.run { getDlfn(second, third) }) list.add(cdlfd.run { getDlfn(second, third) }) fileDexDir.listFiles()?.forEach { it?.name.let { fn -> if (versionFile != fn && oatDir != fn && !list.contains(fn)) { WLog.e(this@PluginManager, "文件:${fn}删除 ") it.delete() } } } if (!fileDexOatDir.exists()) return@run fileDexOatDir.listFiles()?.forEach { it?.name.let { fn -> val oat = fn?.replace(".cur.prof", "") if (versionFile != oat && !list.contains(oat)) { WLog.e(this@PluginManager, "文件:${fn}删除 ") it.delete() } } } } } } /** 可用来当other没有下载 加载完时候,进行等待 **/ fun isLoadSuccessByKey(keyDex: String, keyRes: String): Boolean { var status = false runBlocking { status = if (WXDynamicLoader.instance.loader.isFShowLoadFlag() || cotd.isEmpty()) { if (mapOtherLoadStatus.containsKey(keyDex) && mapOtherLoadStatus.containsKey(keyRes)) mapOtherLoadStatus[keyDex]!!.await() && mapOtherLoadStatus[keyRes]!!.await() else false } else { true } } return status } /** * 按需下载 other 2,other 3 other 4,other 5 (每一个包含dex 和 res apk 2个文件) * 文件须放在 FaceImpl 配置的getBaseL() 服务器目录下面即可 * @param context: 上下问 * @param dexName: dex文件民 * @param resApkName: resApkName文件名 */ fun dynamicLoadPlugin(context: Context, dexName: Pair, resApkName: Pair): Flow { if (cotd.containsKey(dexName.first) && cotd.containsKey(resApkName.first)) { return flowOf(0) } val loader = WXDynamicLoader.instance.loader val face = loader.getDownloadFace() val dexFileUrl = StringBuilder().append(face.getBaseL()).append(dexName.first).toString() val resApkFileUrl = StringBuilder().append(face.getBaseL()).append(resApkName.first).toString() val dynamicHelper = DynamicDownloadPlugin(face) return flow { dynamicHelper.initDynamicPlugin(context, dexFileUrl, dldir, getDlfn(dexName.first, dexName.second)).run { cotd[dexName.first] = dexName.second if (!TextUtils.isEmpty(fileAbsolutePath) && !TextUtils.isEmpty(fileAbsolutePath.trim())) { loader.initDynamicRunTime(context, contentKey, fileAbsolutePath) } else { throw Exception("文件下载异常") } } emit(0) }.zip(flow { dynamicHelper.initDynamicPlugin(context, resApkFileUrl, dldir, getDlfn(resApkName.first, resApkName.second)) cotd[resApkName.first] = resApkName.second emit(0) }) { _, _ -> return@zip 0 }.flowOn(Dispatchers.IO) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Manager/Wgllss-Dynamic-Plugin-Manager/src/main/java/com/wgllss/dynamic/plugin/manager/PluginResource.kt ================================================ package com.wgllss.dynamic.plugin.manager import android.content.res.Resources import com.wgllss.core.units.WLog import java.util.concurrent.ConcurrentHashMap object PluginResource { private val mapLayout by lazy { ConcurrentHashMap() } fun getPluginResources(contentKey: String): Resources { WLog.e(this, "contentKey: $contentKey") return if (mapLayout.containsKey(contentKey) && mapLayout[contentKey] != null) { mapLayout[contentKey]!! } else { val res = PluginManager.instance.getPluginResources(contentKey) mapLayout[contentKey] = res res } } fun getSkinResources(): Resources { return PluginManager.instance.getPluginSkinResources() } fun getWebRes(): Resources { return PluginManager.instance.getWebRes() } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/build.gradle ================================================ plugins { alias(libs.plugins.android.library) } android { compileSdk libs.versions.compileSdk.get().toInteger() namespace "com.wgllss.dynamic.plugin.library" defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { compileOnly libs.appcompat } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/consumer-rules.pro ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/src/main/java/com/wgllss/dynamic/runtime/library/WXDynamicAidlInterface.java ================================================ package com.wgllss.dynamic.runtime.library; public interface WXDynamicAidlInterface extends android.os.IInterface { class Default implements com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface { @Override public void onBind(java.lang.String serviceName, java.lang.String packageName, java.lang.String pluginApkPath) throws android.os.RemoteException { } @Override public void onUnbind(java.lang.String serviceName) throws android.os.RemoteException { } @Override public java.lang.String onAidlCallBack(java.lang.String serviceName, int methodID) throws android.os.RemoteException { return null; } @Override public android.os.IBinder asBinder() { return null; } } abstract class Stub extends android.os.Binder implements com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface { private static final java.lang.String DESCRIPTOR = "com.wgllss.dynamic.plugin.runtime.WXDynamicAidlInterface"; public Stub() { this.attachInterface(this, DESCRIPTOR); } public static com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface))) { return ((com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface) iin); } return new com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_onBind: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); java.lang.String _arg1; _arg1 = data.readString(); java.lang.String _arg2; _arg2 = data.readString(); this.onBind(_arg0, _arg1, _arg2); reply.writeNoException(); return true; } case TRANSACTION_onUnbind: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this.onUnbind(_arg0); reply.writeNoException(); return true; } case TRANSACTION_onAidlCallBack: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); int _arg1; _arg1 = data.readInt(); java.lang.String _result = this.onAidlCallBack(_arg0, _arg1); reply.writeNoException(); reply.writeString(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public void onBind(java.lang.String serviceName, java.lang.String packageName, java.lang.String pluginApkPath) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(serviceName); _data.writeString(packageName); _data.writeString(pluginApkPath); boolean _status = mRemote.transact(Stub.TRANSACTION_onBind, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().onBind(serviceName, packageName, pluginApkPath); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void onUnbind(java.lang.String serviceName) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(serviceName); boolean _status = mRemote.transact(Stub.TRANSACTION_onUnbind, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().onUnbind(serviceName); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public java.lang.String onAidlCallBack(java.lang.String serviceName, int methodID) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(serviceName); _data.writeInt(methodID); boolean _status = mRemote.transact(Stub.TRANSACTION_onAidlCallBack, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().onAidlCallBack(serviceName, methodID); } _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface sDefaultImpl; } static final int TRANSACTION_onBind = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_onUnbind = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_onAidlCallBack = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); public static boolean setDefaultImpl(com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface impl) { if (Stub.Proxy.sDefaultImpl != null) { throw new IllegalStateException("setDefaultImpl() called twice"); } if (impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } void onBind(java.lang.String serviceName, java.lang.String packageName, java.lang.String pluginApkPath) throws android.os.RemoteException; void onUnbind(java.lang.String serviceName) throws android.os.RemoteException; java.lang.String onAidlCallBack(java.lang.String serviceName, int methodID) throws android.os.RemoteException; } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/src/main/java/com/wgllss/dynamic/runtime/library/WXHostActivityDelegate.java ================================================ package com.wgllss.dynamic.runtime.library; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Bundle; import androidx.activity.ComponentActivity; import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; public interface WXHostActivityDelegate { void attachContext(FragmentActivity context, Resources resources); void attachContext(ComponentActivity context, Resources resources); void onCreate(Bundle savedInstanceState); void onRestart(); void onStart(); void onResume(); void onPause(); void onStop(); void onDestroy(); void lazyInitValue(); void onSaveInstanceState(Bundle outState); void onConfigurationChanged(Configuration newConfig); } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/src/main/java/com/wgllss/dynamic/runtime/library/WXHostServiceDelegate.java ================================================ package com.wgllss.dynamic.runtime.library; import android.content.Context; import android.content.Intent; import android.os.IBinder; public interface WXHostServiceDelegate { void attachBaseContext(Context newBase); IBinder onBind(Intent intent); void onCreate(); void onStart(Intent intent, int startId); int onStartCommand(Intent intent, int flags, int startId); boolean onUnbind(Intent intent); void onDestroy(); String callMethodByID(int methodID); } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-Library/src/test/java/com/wgllss/plugin/library/ExampleUnitTest.kt ================================================ package com.wgllss.plugin.library import org.junit.Test import org.junit.Assert.* /** * Example local unit test, which will execute on the development machine (host). * * See [testing documentation](http://d.android.com/tools/testing). */ class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/build.gradle ================================================ plugins { alias(libs.plugins.android.application) } android { namespace 'com.wgllss.dynamic.plugin.runtime' compileSdk libs.versions.compileSdk.get().toInteger() defaultConfig { applicationId "com.wgllss.dynamic.plugin.runtime" minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { debug { // 假如打包后运行闪退,可以在调试模式下打开混淆查看日志找出混淆问题 minifyEnabled false // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled false // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } release { minifyEnabled false // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled false // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } applicationVariants.all { variant -> variant.outputs.all { outputFileName = "classes_wgllss_dynamic_plugin_runtime" } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } lintOptions { abortOnError false } } dependencies { compileOnly libs.appcompat implementation project(':Wgllss-Dynamic-Plugin-Library') compileOnly project(path: ':Wgllss-Dynamic-Plugin-Common-Library') compileOnly project(path: ':Wgllss-Dynamic-Host-Lib') } def createCopyTask(assembleReleaseTask, buildType) { def inputFile = file("${getProject().getBuildDir()}/outputs/apk/release/classes_wgllss_dynamic_plugin_runtime") def outputFile = file("${rootProject.getBuildDir()}/classes_wgllss_dynamic_plugin_runtime") if (outputFile.exists()) { outputFile.delete() } return tasks.create("assembleCopy", Copy) { group = 'other' description = "复制json到 指定输出目录" from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn(assembleReleaseTask.name) } tasks.whenTaskAdded { task -> if (task.name == "assembleRelease") { createCopyTask(task, "release") } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/consumer-rules.pro ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/HostComposePluginActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.wgllss.core.activity.compose.BaseComposeActivity; import com.wgllss.dynamic.host.lib.classloader.PluginKey; import com.wgllss.dynamic.runtime.library.WXHostActivityDelegate; import java.io.File; public class HostComposePluginActivity extends BaseComposeActivity { private PluginClassLoader pluginDexClassLoader; private Resources pluginResources; private WXHostActivityDelegate mHostDelegate; private String skinPackageName; private boolean isFirst = true; private String pluginApkPath = ""; private String activityName = ""; private String privatePackage = ""; @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putString(PluginKey.pluginApkPathKey, pluginApkPath); outState.putString(PluginKey.activityNameKey, activityName); outState.putString(PluginKey.privatePackageKey, privatePackage); if (mHostDelegate != null) mHostDelegate.onSaveInstanceState(outState); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { //适配刘海屏 WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; getWindow().setAttributes(lp); } getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); getWindow().setStatusBarColor(Color.TRANSPARENT); super.onCreate(savedInstanceState); if (savedInstanceState == null) { if (getIntent() != null) { pluginApkPath = getIntent().getStringExtra(PluginKey.pluginApkPathKey); activityName = getIntent().getStringExtra(PluginKey.activityNameKey); privatePackage = getIntent().getStringExtra(PluginKey.privatePackageKey); } else { throw new RuntimeException("There are no pluginApkPath, activityName, or privatePackage parameters in the intent"); } } else { pluginApkPath = savedInstanceState.getString(PluginKey.pluginApkPathKey); activityName = savedInstanceState.getString(PluginKey.activityNameKey); privatePackage = savedInstanceState.getString(PluginKey.privatePackageKey); } new File(pluginApkPath).setReadOnly(); new File(getDir("dex", Context.MODE_PRIVATE).getAbsolutePath()).setReadOnly(); pluginDexClassLoader = new PluginClassLoader(privatePackage, pluginApkPath, getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(), null, getClassLoader()); int flags = (PackageManager.GET_META_DATA | PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS | PackageManager.GET_RECEIVERS); PackageManager packageManager = getApplicationContext().getPackageManager(); PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginApkPath, flags); ApplicationInfo applicationInfo = packageInfo.applicationInfo; applicationInfo.sourceDir = pluginApkPath; applicationInfo.publicSourceDir = pluginApkPath; try { pluginResources = packageManager.getResourcesForApplication(applicationInfo); skinPackageName = applicationInfo.packageName; mHostDelegate = pluginDexClassLoader.getInterface(WXHostActivityDelegate.class, activityName); mHostDelegate.attachContext(this, pluginResources); mHostDelegate.onCreate(savedInstanceState); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onRestart() { super.onRestart(); if (mHostDelegate != null) mHostDelegate.onRestart(); } @Override protected void onStart() { super.onStart(); if (mHostDelegate != null) mHostDelegate.onStart(); } @Override protected void onResume() { super.onResume(); if (mHostDelegate != null) mHostDelegate.onResume(); } @Override protected void onPause() { super.onPause(); if (mHostDelegate != null) mHostDelegate.onPause(); } @Override protected void onStop() { super.onStop(); if (mHostDelegate != null) mHostDelegate.onStop(); } @Override protected void onDestroy() { super.onDestroy(); if (mHostDelegate != null) mHostDelegate.onDestroy(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { if (isFirst) { isFirst = false; if (mHostDelegate != null) mHostDelegate.lazyInitValue(); } } } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); if (mHostDelegate != null) mHostDelegate.onConfigurationChanged(newConfig); } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/HostPluginActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.MenuProvider; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import com.wgllss.core.activity.BaseActivity; import com.wgllss.dynamic.host.lib.classloader.PluginKey; import com.wgllss.dynamic.runtime.library.WXHostActivityDelegate; import java.io.File; public class HostPluginActivity extends BaseActivity { private PluginClassLoader pluginDexClassLoader; private Resources pluginResources; private WXHostActivityDelegate mHostDelegate; private String skinPackageName; private boolean isFirst = true; private String pluginApkPath = ""; private String activityName = ""; private String privatePackage = ""; @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putString(PluginKey.pluginApkPathKey, pluginApkPath); outState.putString(PluginKey.activityNameKey, activityName); outState.putString(PluginKey.privatePackageKey, privatePackage); if (mHostDelegate != null) mHostDelegate.onSaveInstanceState(outState); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { //适配刘海屏 WindowManager.LayoutParams lp = getWindow().getAttributes(); lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; getWindow().setAttributes(lp); } getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); getWindow().setStatusBarColor(Color.TRANSPARENT); super.onCreate(savedInstanceState); if (savedInstanceState == null) { if (getIntent() != null) { pluginApkPath = getIntent().getStringExtra(PluginKey.pluginApkPathKey); activityName = getIntent().getStringExtra(PluginKey.activityNameKey); privatePackage = getIntent().getStringExtra(PluginKey.privatePackageKey); } else { throw new RuntimeException("There are no pluginApkPath, activityName, or privatePackage parameters in the intent"); } } else { pluginApkPath = savedInstanceState.getString(PluginKey.pluginApkPathKey); activityName = savedInstanceState.getString(PluginKey.activityNameKey); privatePackage = savedInstanceState.getString(PluginKey.privatePackageKey); } new File(pluginApkPath).setReadOnly(); new File(getDir("dex", Context.MODE_PRIVATE).getAbsolutePath()).setReadOnly(); pluginDexClassLoader = new PluginClassLoader(privatePackage, pluginApkPath, getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(), null, getClassLoader()); int flags = (PackageManager.GET_META_DATA | PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS | PackageManager.GET_RECEIVERS); PackageManager packageManager = getApplicationContext().getPackageManager(); PackageInfo packageInfo = packageManager.getPackageArchiveInfo(pluginApkPath, flags); ApplicationInfo applicationInfo = packageInfo.applicationInfo; applicationInfo.sourceDir = pluginApkPath; applicationInfo.publicSourceDir = pluginApkPath; try { pluginResources = packageManager.getResourcesForApplication(applicationInfo); skinPackageName = applicationInfo.packageName; mHostDelegate = pluginDexClassLoader.getInterface(WXHostActivityDelegate.class, activityName); mHostDelegate.attachContext(this, pluginResources); mHostDelegate.onCreate(savedInstanceState); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onRestart() { super.onRestart(); if (mHostDelegate != null) mHostDelegate.onRestart(); } @Override protected void onStart() { super.onStart(); if (mHostDelegate != null) mHostDelegate.onStart(); } @Override protected void onResume() { super.onResume(); if (mHostDelegate != null) mHostDelegate.onResume(); } @Override protected void onPause() { super.onPause(); if (mHostDelegate != null) mHostDelegate.onPause(); } @Override protected void onStop() { super.onStop(); if (mHostDelegate != null) mHostDelegate.onStop(); } @Override protected void onDestroy() { super.onDestroy(); if (mHostDelegate != null) mHostDelegate.onDestroy(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { if (isFirst) { isFirst = false; if (mHostDelegate != null) mHostDelegate.lazyInitValue(); } } } @Override public void onPointerCaptureChanged(boolean hasCapture) { super.onPointerCaptureChanged(hasCapture); } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); if (mHostDelegate != null) mHostDelegate.onConfigurationChanged(newConfig); } @Override public void initControl(Bundle savedInstanceState) { } @Override public void bindEvent() { } @Override public void initValue() { } @Override public void addMenuProvider(@NonNull MenuProvider provider, @NonNull LifecycleOwner owner, @NonNull Lifecycle.State state) { } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/HostPluginService.java ================================================ package com.wgllss.dynamic.plugin.runtime; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import androidx.annotation.Nullable; import com.wgllss.dynamic.host.lib.classloader.PluginKey; import com.wgllss.dynamic.runtime.library.WXDynamicAidlInterface; import com.wgllss.dynamic.runtime.library.WXHostServiceDelegate; import java.io.File; import java.util.HashMap; import java.util.LinkedHashMap; public abstract class HostPluginService extends Service { private PluginClassLoader pluginDexClassLoader; private HashMap map; @Nullable @Override public IBinder onBind(Intent intent) { initPluginService(intent, true); return new WXDynamicAidlInterface.Stub() { @Override public void onBind(String serviceName, String packageName, String pluginApkPath) throws RemoteException { android.util.Log.e("HostPluginService", "onBind(String serviceName):" + serviceName + "packageName:" + packageName + "pluginApkPath:" + pluginApkPath); initPluginService(new Intent().putExtra(PluginKey.serviceNameKey, serviceName).putExtra(PluginKey.privatePackageKey, packageName).putExtra(PluginKey.pluginApkPathKey, pluginApkPath), true); } @Override public void onUnbind(String serviceName) throws RemoteException { HostPluginService.this.onUnbind(new Intent().putExtra(PluginKey.serviceNameKey, serviceName)); } @Override public String onAidlCallBack(String serviceName, int methodID) throws RemoteException { if (map != null && map.containsKey(serviceName)) { return map.get(serviceName).callMethodByID(methodID); } return null; } }; } @Override public void onCreate() { super.onCreate(); } @Override public void onStart(Intent intent, int startId) { if (map != null) { for (WXHostServiceDelegate service : map.values()) { if (service != null) service.onStart(intent, startId); } } super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { initPluginService(intent, false); String serviceName = intent.getStringExtra(PluginKey.serviceNameKey); if (map.containsKey(serviceName) && map.get(serviceName) != null) { map.get(serviceName).onStartCommand(intent, flags, startId); map.get(serviceName).onStart(intent, startId); } return onStartCommand(); } public abstract int onStartCommand(); @Override public boolean onUnbind(Intent intent) { String serviceName = intent.getStringExtra(PluginKey.serviceNameKey); if (map.containsKey(serviceName)) { map.get(serviceName).onUnbind(intent); map.remove(serviceName); String bindKey = new StringBuilder(serviceName).append("_bind").toString(); map.remove(bindKey); } return super.onUnbind(intent); } @Override public void onDestroy() { if (map != null) { for (WXHostServiceDelegate service : map.values()) { if (service != null) service.onDestroy(); } } super.onDestroy(); } private void initPluginService(Intent intent, boolean isOnBind) { try { if (map == null) { map = new LinkedHashMap(); } if (intent != null) { String serviceName = intent.getStringExtra(PluginKey.serviceNameKey); if (!map.containsKey(serviceName)) { String pluginApkPath = intent.getStringExtra(PluginKey.pluginApkPathKey); String privatePackage = intent.getStringExtra(PluginKey.privatePackageKey); new File(pluginApkPath).setReadOnly(); new File(getDir("dex", Context.MODE_PRIVATE).getAbsolutePath()).setReadOnly(); pluginDexClassLoader = new PluginClassLoader(privatePackage, pluginApkPath, getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(), null, getClassLoader()); WXHostServiceDelegate serviceDelegate = pluginDexClassLoader.getInterface(WXHostServiceDelegate.class, serviceName); serviceDelegate.attachBaseContext(this); serviceDelegate.onCreate(); map.put(serviceName, serviceDelegate); } String bindKey = new StringBuilder(serviceName).append("_bind").toString(); if (isOnBind && !map.containsKey(bindKey)) { map.get(serviceName).onBind(intent); map.put(bindKey, null); } } } catch (Exception e) { e.printStackTrace(); } } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginClassLoader.java ================================================ package com.wgllss.dynamic.plugin.runtime; import com.wgllss.dynamic.host.lib.classloader.WXClassLoader; public class PluginClassLoader extends WXClassLoader { private String privatePackage; public PluginClassLoader(String privatePackage, String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(dexPath, optimizedDirectory, librarySearchPath, parent); this.privatePackage = privatePackage; } @Override public Class loadClass(String className) throws ClassNotFoundException { if (!className.contains(privatePackage)) { return parent.loadClass(className); } Class clazz = findLoadedClass(className); if (clazz == null) { try { clazz = findClass(className); } catch (ClassNotFoundException e) { } if (clazz == null) { try { clazz = super.loadClass(className); } catch (ClassNotFoundException e) { clazz = parent.loadClass(className); } } } return clazz; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginProcessStartNotStickyService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginProcessStartNotStickyService extends HostPluginService { @Override public int onStartCommand() { return START_NOT_STICKY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginProcessStartRedeliverIntentService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginProcessStartRedeliverIntentService extends HostPluginService { @Override public int onStartCommand() { return START_REDELIVER_INTENT; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginProcessStartStickyCompatibilityService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginProcessStartStickyCompatibilityService extends HostPluginService { @Override public int onStartCommand() { return START_STICKY_COMPATIBILITY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginProcessStartStickyService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginProcessStartStickyService extends HostPluginService { @Override public int onStartCommand() { return START_STICKY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleInstanceActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleInstanceActivity extends HostPluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleInstanceComposeActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleInstanceComposeActivity extends HostComposePluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleTaskActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleTaskActivity extends HostPluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleTaskComposeActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleTaskComposeActivity extends HostComposePluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleTopActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleTopActivity extends HostPluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginSingleTopComposeActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginSingleTopComposeActivity extends HostComposePluginActivity { } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStandardActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStandardActivity extends HostPluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStandardComposeActivity.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStandardComposeActivity extends HostComposePluginActivity{ } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStartNotStickyService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStartNotStickyService extends HostPluginService { @Override public int onStartCommand() { return START_NOT_STICKY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStartRedeliverIntentService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStartRedeliverIntentService extends HostPluginService { @Override public int onStartCommand() { return START_REDELIVER_INTENT; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStartStickyCompatibilityService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStartStickyCompatibilityService extends HostPluginService { @Override public int onStartCommand() { return START_STICKY_COMPATIBILITY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/main/java/com/wgllss/dynamic/plugin/runtime/PluginStartStickyService.java ================================================ package com.wgllss.dynamic.plugin.runtime; public class PluginStartStickyService extends HostPluginService { @Override public int onStartCommand() { return START_STICKY; } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-SDK/Wgllss-Dynamic-Plugin-RunTime-Apk/src/test/java/com/wgllss/dynamic/runtime/ExampleUnitTest.kt ================================================ package com.wgllss.dynamic.runtime import org.junit.Test import org.junit.Assert.* /** * Example local unit test, which will execute on the development machine (host). * * See [testing documentation](http://d.android.com/tools/testing). */ class ExampleUnitTest { @Test fun addition_isCorrect() { assertEquals(4, 2 + 2) } } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/.gitignore ================================================ /build ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/build.gradle ================================================ plugins { alias(libs.plugins.android.application) } android { namespace 'com.wgllss.sample.web.assets.source' compileSdk libs.versions.compileSdk.get().toInteger() defaultConfig { applicationId "com.wgllss.sample.web.assets.source" minSdkVersion libs.versions.minSdk.get().toInteger() targetSdkVersion libs.versions.targetSdkVersion.get().toInteger() versionCode 1 versionName "1.0" } buildTypes { debug { // 假如打包后运行闪退,可以在调试模式下打开混淆查看日志找出混淆问题 minifyEnabled false // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled false // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } release { minifyEnabled false // 开启混淆 shrinkResources false // 启动资源压缩 zipAlignEnabled false // 开启zipalign优化 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } applicationVariants.all { variant -> variant.outputs.all { outputFileName = "classes_business_web_res.apk" } } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } def createCopyTask(assembleReleaseTask, buildType) { def inputFile = file("${getProject().getBuildDir()}/outputs/apk/release/classes_business_web_res.apk") def outputFile = file("${rootProject.getBuildDir()}/classes_business_web_res") if (outputFile.exists()) { outputFile.delete() } return tasks.create("assembleCopy", Copy) { group = 'other' description = "复制json到 指定输出目录" from(inputFile.getParent()) { include(inputFile.name) rename { outputFile.name } } into(outputFile.getParent()) }.dependsOn(assembleReleaseTask.name) } tasks.whenTaskAdded { task -> if (task.name == "assembleRelease") { createCopyTask(task, "release") } // if (task.name == "cleanJson") { // createVersionJson(task, "Release") // } } dependencies { } ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/src/main/AndroidManifest.xml ================================================ ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/src/main/assets/css/main.8f39d45c.css ================================================ @charset "UTF-8";*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}:after,:before{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;cursor:default;line-height:1.5;overflow-wrap:break-word;-moz-tab-size:4;-o-tab-size:4;tab-size:4}:where(body){margin:0}:where(h1){font-size:2em;margin:.67em 0}:where(dl,ol,ul) :where(dl,ol,ul){margin:0}:where(hr){color:inherit;height:0}:where(nav) :where(ol,ul){list-style-type:none;padding:0}:where(nav li):before{content:"\200B";float:left}:where(pre){font-family:monospace,monospace;font-size:1em;overflow:auto}:where(abbr[title]){text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}:where(b,strong){font-weight:bolder}:where(code,kbd,samp){font-family:monospace,monospace;font-size:1em}:where(small){font-size:80%}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}:where(iframe){border-style:none}:where(svg:not([fill])){fill:currentColor}:where(table){border-collapse:collapse;border-color:inherit;text-indent:0}:where(button,input,select){margin:0}:where(button,[type=button i],[type=reset i],[type=submit i]){-webkit-appearance:button}:where(fieldset){border:.01333rem solid #a0a0a0}:where(progress){vertical-align:baseline}:where(textarea){margin:0;resize:vertical}:where([type=search i]){-webkit-appearance:textfield;outline-offset:-.02667rem}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}:where(dialog){background-color:#fff;border:solid;color:#000;height:-moz-fit-content;height:-webkit-fit-content;height:fit-content;left:0;margin:auto;padding:1em;position:absolute;right:0;width:-moz-fit-content;width:-webkit-fit-content;width:fit-content}:where(dialog:not([open])){display:none}:where(details>summary:first-of-type){display:list-item}:where([aria-busy=true i]){cursor:progress}:where([aria-controls]){cursor:pointer}:where([aria-disabled=true i],[disabled]){cursor:not-allowed}:where([aria-hidden=false i][hidden]){display:inline;display:initial}:where([aria-hidden=false i][hidden]:not(:focus)){clip:rect(0,0,0,0);position:absolute}html{font-family:system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,PingFang SC,sans-serif}code,kbd,pre,samp{font-family:Menlo,Consolas,Roboto Mono,monospace}a{-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ios{cursor:pointer}@font-face{font-family:icomoon;font-style:normal;font-weight:400;src:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/icomoon.1adfe1c60f03e5bc8bd0.ttf) format("truetype"),url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/icomoon.be9154276c565176b74c.woff) format("woff"),url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/icomoon.c3831930ea32fc59358b.svg) format("svg")}[class*=" icon-"],[class^=icon-]{speak:none;-webkit-font-feature-settings:normal;font-feature-settings:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:icomoon!important;font-style:normal;font-variant:normal;font-weight:400;line-height:1;text-transform:none}.icon-logo{color:#fff}.icon-play:before{content:""}.icon-href:before{content:""}.icon-radio:before{content:""}.icon-radio-checked:before{content:""}.icon-talk:before{content:""}.icon-checkbox:before{content:""}.icon-checkbox-checked:before{content:""}.icon-flag:before{content:""}.icon-image:before{content:""}.icon-logo:before{content:""}.icon-like:before{content:""}.icon-liked:before{content:""}.icon-timeline:before{content:""}.icon-read:before{content:""}.icon-audio:before{content:""}.icon-arrow:before{content:""}.icon-live:before{content:""}.icon-quotes-left:before{content:""}.icon-quotes-right:before{content:""}.icon-close:before{content:""}.icon-weixin:before{content:""}.icon-qq:before{content:""}.icon-weibo:before{content:""}.icon-switch:before{content:""}.icon-email:before{content:""}.icon-talking:before{content:""}.icon-vip{background:#f1c37e url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/vip.35d08192e94b04059f4f.png) 50%/100% 100% no-repeat;border-radius:.06667rem;display:inline-block;height:.48rem;width:.72rem}.main.main-paid .article .article-body:after{background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#fff),to(hsla(0,0%,100%,0)));background:linear-gradient(0deg,#fff 0,hsla(0,0%,100%,0));bottom:0;content:"";height:4.26667rem;left:0;pointer-events:none;position:absolute;width:100%}.main.main-paid .main-openApp{display:none}.main.main-paid .expend-title{pointer-events:none;position:relative;z-index:10}.banner-vipBanner{width:100%}.article-pay{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:0 0 .4rem}.article-pay.article-pay-collect .pay-price,.article-pay.article-pay-vip .pay-price{background:#f5f7f9;color:#333;font-weight:400}.article-pay .pay-buyCount-wrap{-webkit-box-align:center;-ms-flex-align:center;-ms-flex-item-align:stretch;align-items:center;align-self:stretch;color:#666;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.32rem;margin:.26667rem 0 .64rem;text-align:center}.article-pay .pay-buyCount-wrap .pay-wordCount{font-size:.4rem;font-weight:600}.article-pay .pay-buyCount-wrap:after,.article-pay .pay-buyCount-wrap:before{-webkit-box-flex:1;-ms-flex-positive:1;background:#ddd;content:"";flex-grow:1;height:1PX;min-width:.13333rem;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.article-pay .pay-buyCount-wrap:before{margin:0 .33333rem 0 .13333rem}.article-pay .pay-buyCount-wrap:after{margin:0 .13333rem 0 .33333rem}.article-pay .pay-buyCount-wrap .icon-arrow{color:#999;margin:0 0 0 .2rem;-webkit-transform:rotate(90deg);transform:rotate(90deg)}.article-pay .pay-buyCount{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;overflow:hidden}.article-pay .pay-buyCount,.article-pay .pay-record{display:-webkit-box;display:-ms-flexbox;display:flex}.article-pay .pay-record{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.article-pay .pay-record .s-shrink{-ms-flex-negative:0;flex-shrink:0}.article-pay .pay-record .s-collectName{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.article-pay .pay-record .s-strong{color:#333;font-weight:500}.article-pay .pay-collect,.article-pay .pay-price{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:#ee1a1a;border-radius:.53333rem;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;font-weight:500;font-weight:600;height:1.06667rem;justify-content:center;margin:.16rem 0;min-width:66%;padding:0 .13333rem;white-space:nowrap}.article-pay .pay-collect .s-small,.article-pay .pay-price .s-small{font-size:.34667rem;font-weight:400;margin:0 0 0 .2rem}.article-pay .pay-vip{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-image:-webkit-gradient(linear,left top,right top,from(rgba(195,143,58,.25)),to(rgba(195,143,58,.5)));background-image:linear-gradient(90deg,rgba(195,143,58,.25),rgba(195,143,58,.5));border-radius:1.33333rem;color:#783c00;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;font-weight:500;height:1.06667rem;justify-content:center;margin:.16rem 0;min-width:66%;padding:0 .13333rem;position:relative;white-space:nowrap}.article-pay .pay-vip .s-bubble{background:#783c00;border-radius:.26667rem;color:#fff;font-size:.29333rem;font-weight:600;line-height:.53333rem;padding:0 .2rem;position:absolute;right:1.06667rem;text-align:center;top:-.4rem;-webkit-transform:translateX(50%);transform:translateX(50%);z-index:10}.article-pay .pay-vip .s-bubble:after{border:.26667rem solid transparent;border-left-color:#783c00;bottom:-.13333rem;content:"";height:0;left:50%;position:absolute;width:0;z-index:-1}.article-pay .pay-vip-tip{background:#333;border-radius:.26667rem;color:#fff;font-size:.29333rem;font-weight:600;line-height:.53333rem;padding:0 .2rem;position:absolute;right:-.8rem;text-align:center;top:-.4rem;z-index:10}.article-pay .pay-vip-tip .tip-fullPrice{color:#fff;font-size:.29333rem;font-weight:200;opacity:.8;text-align:center;text-decoration:line-through}.article-pay .pay-vip-tip:after{border:.26667rem solid transparent;border-left-color:#333;bottom:-.13333rem;content:"";height:0;left:50%;position:absolute;width:0;z-index:-1}.article-pay .pay-bugNotes{color:#999;font-size:.32rem;font-weight:400;margin:.16rem 0}.article-pay .pay-bugNotes a{color:#666}.article-payCollect{-webkit-box-orient:vertical;-webkit-box-direction:normal;background:#f5f7f9;border-radius:.26667rem;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:.4rem 0;padding:.16rem .32rem}.article-payCollect .s-title{color:#999;font-size:.32rem;padding:.08rem 0 0}.article-payCollect .payCollect-content{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;padding:.32rem 0}.article-payCollect .payCollect-cover{-ms-flex-negative:0;border-radius:.08rem;flex-shrink:0;height:1.33333rem;margin:0 .21333rem 0 0;-o-object-fit:cover;object-fit:cover;overflow:hidden;width:1.33333rem}.article-payCollect .payCollect-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden}.article-payCollect .payCollect-name{color:#333;font-size:.42667rem;line-height:2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.article-payCollect .payCollect-count{color:#999;font-size:.32rem}.article-payCollect .paidCollect-line{background-color:#ddd;height:.01333rem;margin:0 0 .16rem;-webkit-transform:scaleY(.5);transform:scaleY(.5);width:100%}.article-payCollect .payCollect-recommend{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;height:1.17333rem;overflow:hidden;padding:0 .18667rem}.article-payCollect .recommend-tip{-ms-flex-negative:0;color:#999;flex-shrink:0;font-size:.32rem;font-weight:500;margin:0 .4rem 0 0}.article-payCollect .recommend-title{-webkit-box-flex:1;-ms-flex-positive:1;color:#666;flex-grow:1;font-size:.4rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.article-payCollect .icon-arrow{-ms-flex-negative:0;color:#b4b4b4;flex-shrink:0;font-size:.26667rem;margin:0 0 0 .06667rem}.article-payVip-recommend{-webkit-box-orient:vertical;-webkit-box-direction:normal;background:#f5f7f9;border-radius:.26667rem;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:.4rem 0;padding:.16rem .32rem}.article-payVip-recommend.article-payVip-recommend-content{padding:0 .32rem}.article-payVip-recommend .payVip-swiper{overflow:hidden}.article-payVip-recommend .swiper-pagination{-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center}.article-payVip-recommend .swiper-pagination .swiper-pagination-bullet{background:rgba(0,0,0,.2);border-radius:50%;display:block;height:.16rem;margin:0 .06667rem;width:.16rem}.article-payVip-recommend .swiper-pagination .swiper-pagination-bullet.swiper-pagination-bullet-active{background:rgba(0,0,0,.5);border-radius:.08rem;width:.32rem}.article-payVip-recommend .s-header{-webkit-box-pack:justify;-ms-flex-pack:justify;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-between}.article-payVip-recommend .s-header a,.article-payVip-recommend .s-title{color:#999;font-size:.32rem;padding:.08rem 0 0}.article-payVip-recommend ul{list-style:none;margin:0;padding:0}.article-payVip-recommend .s-item{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;padding:.32rem 0}.article-payVip-recommend .s-cover{-ms-flex-negative:0;border-radius:.08rem;flex-shrink:0;height:1.6rem;margin:0 .21333rem 0 0;-o-object-fit:cover;object-fit:cover;overflow:hidden;width:2.13333rem}.article-payVip-recommend .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden}.article-payVip-recommend .s-name{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:#333;display:-webkit-box;font-size:.37333rem;line-height:.48rem;max-height:.96rem;min-height:.96rem;overflow:hidden;text-overflow:ellipsis}.article-payVip-recommend .s-desc{color:#999;font-size:.32rem;line-height:1;margin:.21333rem 0 0}.article-payVip-recommend .s-desc .s-price{font-weight:600;margin:0 .26667rem 0 0}.article-payVip-recommend .s-line{background-color:#ddd;height:.01333rem;margin:0 0 .16rem;-webkit-transform:scaleY(.5);transform:scaleY(.5);width:100%}body{background:#fff;margin:0 auto;max-width:750PX;overflow-x:hidden;overflow-y:auto;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}a{color:#1b88ee;text-decoration:none}figure{margin:0}.main{font-size:.48rem;padding:0 .53333rem}.main .article-title{color:#333;font-size:.66667rem;font-weight:500;letter-spacing:0;line-height:.90667rem;margin:.53333rem 0}.main .article-info{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-between;margin:.13333rem 0 .66667rem}.main .article-info .s-avatar{border-radius:50%;height:.86667rem;margin-right:.13333rem;width:.86667rem}.main .article-info .s-author{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-flex:1;-ms-flex-positive:1;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;flex-grow:1;line-height:1.5;overflow:hidden}.main .article-info address{color:#333;font-size:.34667rem;font-style:normal;letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.main .article-info address a{color:#333}.main .article-info .s-time{color:#b4b4b4;font-size:.32rem}.main .article-info .s-comment{-ms-flex-negative:0;background:#f5f7f9;border-radius:.38667rem;flex-shrink:0;font-size:.37333rem}.main .article-info .s-comment a{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;height:.77333rem;line-height:.77333rem;padding:0 .32rem}.main .article-info .s-comment a:before{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/discuss2.13b37e82da55f366d844.png) 50% no-repeat;background-size:100% 100%;content:"";height:.53333rem;margin:0 .13333rem 0 0;width:.53333rem}.main .article-body{color:#333;font-weight:400;letter-spacing:0;line-height:.74667rem;overflow:hidden;overflow-wrap:break-word;position:relative;text-align:justify}.main .article-body.article-body-fold{max-height:200vh}.main .article-body.article-body-fold:after{background:-webkit-gradient(linear,left bottom,left top,color-stop(0,#fff),to(hsla(0,0%,100%,0)));background:linear-gradient(0deg,#fff 0,hsla(0,0%,100%,0));bottom:0;content:"";height:4.26667rem;left:0;pointer-events:none;position:absolute;width:100%}.main .article-body .preset-original-title{color:#666;line-height:.8rem;margin-top:.36rem;text-align:justify;word-break:break-all}.main .article-body .preset-original-title:before{content:"「";margin:0 .08rem 0 -.13333rem}.main .article-body .preset-original-title:after{content:"」";margin-left:.08rem}.main .article-body blockquote{border-left:.06667rem solid #ddd;border-radius:.02667rem;color:#666;font-size:.45333rem;margin:0;padding:0 0 0 .26667rem}.main .article-body pre{white-space:pre-wrap}.main .article-body ol{padding-left:1em}.main .article-body .preset-text-border{border:.02667rem solid #000}.main .article-body .hljs{background-color:#f5f7f9;font-size:.75em;padding:.6em .8em!important}.main .unfold-wrap{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;justify-content:center;padding:.13333rem 0}.main .unfold-wrap .icon-arrow{font-size:.29333rem;margin:0 0 0 .2rem;-webkit-transform:rotate(90deg);transform:rotate(90deg)}.main .main-openApp{border:.02667rem solid #ee1a1a;border-radius:.58667rem;color:#ee1a1a;font-size:.45333rem;height:1.17333rem;margin:.53333rem auto .8rem;max-width:100%;text-align:center;width:90%}.main .main-openApp,.rumor{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center}.rumor{background:rgba(254,93,16,.05);border-radius:.08rem;color:#fe5d10;font-size:.32rem;height:.66667rem;letter-spacing:0;line-height:1;margin:.32rem 0 0}.rumor:before{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/rumor.fb75769dd96838373339.png) 50%/100% 100% no-repeat;content:"";height:.4rem;margin:0 .10667rem 0 0;width:.4rem}.area-topBanner{max-width:100%;overflow:hidden}.loading{-webkit-box-pack:center;-ms-flex-pack:center;display:none;justify-content:center;margin:.13333rem 0}.loading.show{display:-webkit-box;display:-ms-flexbox;display:flex}.loading .circular{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;height:.93333rem;-webkit-transform-origin:center center;transform-origin:center center;width:.93333rem}.loading .path{stroke-dasharray:1,200;stroke-dashoffset:0;stroke:#ccc;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes rotate{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-.46667rem}to{stroke-dasharray:89,200;stroke-dashoffset:-1.65333rem}}@keyframes dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-.46667rem}to{stroke-dasharray:89,200;stroke-dashoffset:-1.65333rem}}.article-footer{color:#999;font-size:.42667rem;line-height:.58667rem}.article-footer .s-statement{font-size:.37333rem;margin:.26667rem 0}.article-footer .s-info{margin:.13333rem 0}.footer{-webkit-box-sizing:content-box;box-sizing:content-box;height:2rem;padding-bottom:calc(env(safe-area-inset-bottom) - 16PX)}.hide-comment .comment,.hide-comment .main .article-info .s-comment,.hide-comment .topNav .s-comment{display:none}.toutiao .keyword-search{color:#404040;pointer-events:none}.miniprogram .m-photo .s-tip,.miniprogram .m-photoSet .s-tip,.miniprogram .m-video .s-tip,.miniprogram .main-openApp,.miniprogram .recommend .recommend-item .s-openApp,.newsapp .m-photo .s-tip,.newsapp .m-photoSet .s-tip,.newsapp .m-video .s-tip,.newsapp .main-openApp,.newsapp .recommend .recommend-item .s-openApp,.toutiao .comment,.toutiao .m-photo .s-tip,.toutiao .m-photoSet .s-tip,.toutiao .m-video .s-tip,.toutiao .recommend .recommend-item .s-openApp{display:none}.widget-slider{max-width:10rem!important}.widget-slider .widget-slider-article-simple{max-width:10rem}.pc .comment-open-app,.pc .m-photo .s-tip,.pc .m-photoSet .s-tip,.pc .m-video .s-tip,.pc .main-openApp,.pc .recommend .recommend-item .s-openApp{display:none}.pc .author-homePage{pointer-events:none}@media screen and (min-width:850px){body .floatMenu .floatMenu-content{right:-1.2rem}}body.paid .topNav{background:#fff}body.paid .topNav .s-comment.show{display:none}body.paid .topNav .s-back{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/home.470d92a5fdedaaba3191.png) 50% no-repeat;background-size:.66667rem .66667rem;padding:.26667rem .16rem .26667rem .13333rem}body.paid .topNav .s-search{background:#f5f7f9}body.paid .topNav .s-search .hot-word{color:#666}body.paid .topNav .s-search .hot-word:before{background-image:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/search-light.7f1f63c1c663f9ccd6b2.png);margin:0 .13333rem 0 0}body.paid .topNav .s-channel{display:none}body.paid .topNav .topNav-user{display:block}body.paid .main .article-info .s-comment{display:none}body.paid .m-photo img,body.paid .m-photoSet img,body.paid .m-video img{background:#e5e5e5 50%/3.6rem 2.69333rem no-repeat}body.paid .article-footer .s-info,body.paid .article-footer .s-statement{display:none}body.paid .main .article-info{pointer-events:none}body.paid .backflow-floating,body.paid .comment,body.paid .m-photo .s-tip,body.paid .m-photoSet .s-tip,body.paid .m-video .s-tip,body.paid .main-openApp,body.paid .recommend .recommend-item .s-openApp{display:none}.header,.topNav{height:1.28rem;max-width:750PX;width:100%}.topNav{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:#ef4645;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;left:0;margin:0 auto;position:fixed;right:0;top:0;z-index:100}.topNav .s-back{-ms-flex-item-align:stretch;-ms-flex-negative:0;align-self:stretch;background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/logo.59f1e7f191ea16f90f29.png) 50% no-repeat;background-size:1.2rem .58667rem;-webkit-box-sizing:content-box;box-sizing:content-box;flex-shrink:0;font-size:0;padding:.26667rem .16rem .26667rem .4rem;width:1.2rem}.topNav .s-line{background:hsla(0,0%,100%,.5);height:.42667rem;width:1PX}.topNav .s-channel{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;-ms-flex-item-align:stretch;align-items:center;align-self:stretch;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;font-size:.4rem;font-weight:400;justify-content:center;margin:0 .4rem 0 .16rem}.topNav .s-search{-webkit-box-pack:start;-ms-flex-pack:start;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;background:rgba(0,0,0,.1);border-radius:.46667rem;color:#fff;font-size:.4rem;height:.85333rem;justify-content:flex-start;margin:0 .4rem 0 0;padding:0 .13333rem 0 .26667rem;position:relative}.topNav .s-search,.topNav .s-search .hot-words{-webkit-box-flex:1;-ms-flex-positive:1;display:-webkit-box;display:-ms-flexbox;display:flex;flex-grow:1;overflow:hidden}.topNav .s-search .hot-words{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.topNav .s-search .hot-word{-webkit-box-pack:start;-ms-flex-pack:start;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;align-items:center;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;height:.85333rem;justify-content:flex-start;overflow:hidden}.topNav .s-search .hot-word .s-text{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.topNav .s-search .hot-word:before{-ms-flex-negative:0;background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/search.f764c8e1be1bc69b6b2d.png) no-repeat 50%;background-size:100% 100%;content:"";flex-shrink:0;height:.4rem;margin:0 .05rem 0 0;width:.4rem}.topNav .s-comment{-ms-flex-negative:0;background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/discuss.aae7acd46aa0c6155bb1.png) no-repeat 0 100%;background-size:.66667rem .66667rem;color:#ee1a1a;flex-shrink:0;font-size:.26667rem;font-weight:700;height:.68rem;max-width:0;position:relative;-webkit-transform:scale(0);transform:scale(0)}.topNav .s-comment .s-count{background:#fff;border-radius:.16rem;height:.32rem;line-height:.32rem;margin:0 0 0 .4rem;padding:0 .06667rem}.topNav .s-comment.show{margin:0 .26667rem 0 0;max-width:unset;min-width:.06667rem;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .25s linear;transition:-webkit-transform .25s linear;transition:transform .25s linear;transition:transform .25s linear,-webkit-transform .25s linear}.topNav .topNav-user{background:#f5f7f9 url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/mine.25627349a06a2600881b.png) 50%/.64rem .64rem no-repeat;border-radius:50%;display:none;height:.85333rem;margin:0 .33333rem 0 0;width:.85333rem}.hot-search{bottom:-13.32rem;font-size:.37333rem;position:fixed}.hot-search h3{font-size:.42667rem}.hot-search ul{list-style:none;margin:0;padding:0}.comment{padding:.93333rem 0 .66667rem}.comment h3{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/comment-title.2310fbb7c01acd14cb88.png) 50% no-repeat;background-size:100% 100%;font-size:0;height:.8rem;margin:0 auto;padding:0;width:3.84rem}.comment .comment-list{margin:.42667rem 0 0}.comment .comment-list .comment-card{margin:0 0 .48rem}.comment .comment-list .comment-card header{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-between}.comment .comment-list .comment-card .s-avatar{-ms-flex-negative:0;border-radius:50%;flex-shrink:0;height:.93333rem;margin:0 .2rem 0 0;width:.93333rem}.comment .comment-list .comment-card .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-flex:1;-ms-flex-positive:1;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;flex-grow:1}.comment .comment-list .comment-card .s-nick{color:#333;font-size:.37333rem;line-height:.48rem}.comment .comment-list .comment-card .s-location{color:#b4b4b4;font-size:.29333rem;letter-spacing:0;line-height:.37333rem}.comment .comment-list .comment-card .s-vote{color:#999;font-size:.34667rem;font-weight:500;line-height:.4rem;line-height:.61333rem}.comment .comment-list .comment-card .icon-fav{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/praise.f8b126943a80fffc22b1.png);background-size:100% 100%;display:inline-block;height:.53333rem;margin:0 0 0 .06667rem;vertical-align:top;width:.53333rem}.comment .comment-list .comment-card .s-content{color:#333;font-size:.48rem;letter-spacing:0;margin:.16rem 0 .16rem 1.12rem}.comment .comment-list .comment-card .s-time{color:#b4b4b4;font-size:.32rem;letter-spacing:0;line-height:.45333rem;margin:0 0 0 1.12rem}.comment .comment-link{-ms-flex-pack:distribute;color:#ee1a1a;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.42667rem;font-weight:400;justify-content:space-around}.comment .comment-link a{color:#ee1a1a}.comment .comment-link .icon-arrow{font-size:.24rem;margin:.13333rem 0 .13333rem .06667rem}.comment .comment-empty{color:#333;font-size:.48rem;font-weight:400;letter-spacing:0;margin:1.33333rem 0;text-align:center}.ask{margin:.4rem 0 0;overflow:hidden}.ask h3{color:#333;font-size:.45333rem;font-weight:500;line-height:.66667rem}.ask ul{list-style:none;margin:0;padding:0}.ask li{-webkit-box-orient:vertical;-webkit-box-direction:normal;border-bottom:1px solid #e5e5e5;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden;padding:.32rem 0}.ask li a{color:#333}.ask li:last-child{border-bottom:none}.ask li .s-title{font-size:.48rem}.ask li .s-doctor{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.37333rem}.ask li .s-avatar{border-radius:.26667rem;height:1.06667rem;overflow:hidden;width:1.06667rem}.ask li .s-avatar img{height:auto;width:100%}.ask li .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-size:.37333rem;margin:.32rem 0 .21333rem .13333rem}.ask li .s-info .s-hospital{color:#999;font-size:.34667rem}.ask li .s-detial{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:#666;display:-webkit-box;font-size:.42667rem;letter-spacing:.01333rem;line-height:.66667rem;max-height:1.33333rem;overflow:hidden;text-align:justify;text-overflow:ellipsis}.card-recommend-oneImg{color:#333;font-size:.48rem}.card-recommend-oneImg article{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;min-height:2.89333rem}.card-recommend-oneImg article .s-left{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-flex:1;-ms-flex-positive:1;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;flex-grow:1;justify-content:space-between;min-height:2.33333rem;min-width:0}.card-recommend-oneImg article .s-info{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#999;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.32rem}.card-recommend-oneImg article .s-source{margin:0 .21333rem 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card-recommend-oneImg article .s-tag{color:#f52727}.card-recommend-oneImg article .s-replyCount,.card-recommend-oneImg article .s-tag{-ms-flex-negative:0;flex-shrink:0;margin:0 .21333rem 0 0}.card-recommend-oneImg article .s-openApp{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;align-items:center;border:.02667rem solid #ee1a1a;border-radius:1.33333rem;-webkit-box-sizing:content-box;box-sizing:content-box;color:#ee1a1a;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;font-size:.32rem;height:.58667rem;justify-content:center;padding:0 .24rem}.card-recommend-oneImg article .s-holder{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.card-recommend-oneImg article .s-right{-ms-flex-negative:0;border-radius:.08rem;flex-shrink:0;height:2.22667rem;margin:0 0 0 .4rem;overflow:hidden;position:relative;width:2.90667rem}.card-recommend-oneImg article .s-right img{height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.card-recommend-oneImg article .s-right .icon-play{color:#fff;font-size:.42667rem;left:50%;position:absolute;text-align:center;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);z-index:5}.card-recommend-oneImg article .s-right .s-audioTime{-webkit-box-align:center;-ms-flex-align:center;align-items:center;bottom:.06667rem;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.32rem;position:absolute;right:.06667rem;z-index:5}.card-recommend-oneImg article .s-right .s-audioTime .icon-audio{color:#fff;font-size:.26667rem;margin:0 .13333rem 0 0;text-align:center}.card-recommend-oneImg article h4{-webkit-line-clamp:2;-webkit-box-orient:vertical;color:#333;display:-webkit-box;font-size:.48rem;font-weight:400;line-height:.66667rem;margin:0;max-height:1.33333rem;overflow:hidden;text-overflow:ellipsis}.card-recommend-threeImg{color:#333;font-size:.48rem}.card-recommend-threeImg article{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-height:2.89333rem;padding:.21333rem 0}.card-recommend-threeImg article .s-info{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#999;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.32rem}.card-recommend-threeImg article .s-source{margin:0 .21333rem 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.card-recommend-threeImg article .s-tag{color:#f52727}.card-recommend-threeImg article .s-replyCount,.card-recommend-threeImg article .s-tag{-ms-flex-negative:0;flex-shrink:0;margin:0 .21333rem 0 0}.card-recommend-threeImg article .s-imgs-wrap{margin:.10667rem 0;padding-bottom:25%;position:relative;width:100%}.card-recommend-threeImg article .s-imgs{-webkit-box-pack:justify;-ms-flex-pack:justify;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:space-between;left:0;margin:0;position:absolute;right:0;top:0}.card-recommend-threeImg article .s-imgs img{border-radius:.08rem;max-height:190PX;-o-object-fit:cover;object-fit:cover;overflow:hidden;width:33%}.card-recommend-threeImg article .s-openApp{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;align-items:center;border:.02667rem solid #ee1a1a;border-radius:1.33333rem;-webkit-box-sizing:content-box;box-sizing:content-box;color:#ee1a1a;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;font-size:.32rem;height:.58667rem;justify-content:center;padding:0 .24rem}.card-recommend-threeImg article .s-holder{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.card-recommend-threeImg article h4{color:#333;font-size:.48rem;font-weight:400;line-height:.66667rem;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.recommend{margin:.4rem 0 0;overflow:hidden}.recommend h3{color:#333;font-size:.45333rem;font-weight:500;line-height:.66667rem}.recommend ul{list-style:none;margin:0;padding:0}.recommend li{border-bottom:1px solid #eef1f7}.recommend li:last-child{border-bottom:none}.floatMenu{bottom:0;left:50%;max-width:750PX;opacity:0;pointer-events:none;position:fixed;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:100%;z-index:999}.floatMenu.show{opacity:1;pointer-events:auto;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.floatMenu .floatMenu-content{-webkit-box-orient:vertical;-webkit-box-direction:normal;background:hsla(0,0%,100%,.95);border-radius:.53333rem;-webkit-box-shadow:0 0 .10667rem 0 rgba(0,0,0,.12);box-shadow:0 0 .10667rem 0 rgba(0,0,0,.12);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-size:0;position:absolute;right:.4rem;top:-4.4rem;width:1.06667rem}.floatMenu em{-ms-flex-item-align:center;align-self:center;background:#ddd;height:1PX;width:.74667rem}.floatMenu .floatMenu-home,.floatMenu .floatMenu-toTop{background:50% no-repeat;background-size:.53333rem .53333rem;height:1.2rem}.floatMenu .floatMenu-toTop{background-image:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/menu-toTop.fe4b74d7c16e0758813b.png)}.floatMenu .floatMenu-home{background-image:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/menu-home.86e6b645737e5812a0f5.png)}.m-sectionTitle{margin:.26667rem 0 0;text-align:center}.m-sectionTitle img{height:.98667rem;margin-bottom:.05333rem;width:auto}.m-sectionTitle h3{font-size:.48rem;font-weight:700;line-height:.72rem;margin:0;padding:0}.m-photo{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:center;margin:.66667rem auto .77333rem;width:100%}.m-photo.small-photo .s-tip{display:none}.m-photo .gif-photo:after{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/gif.7d4d9f13d1801ec9b843.png) 50%/1.28rem 1.28rem no-repeat}.m-photo .gif-photo-loading:after,.m-photo .gif-photo:after{bottom:0;content:"";left:0;position:absolute;right:0;top:0;z-index:10}.m-photo .gif-photo-loading:after{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/gif-loading.2f56edd154e8431be2c2.svg) 50%/1.28rem 1.28rem no-repeat}.m-photo .gif-photo-loading .circular{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;height:.93333rem;-webkit-transform-origin:center center;transform-origin:center center;width:.93333rem}.m-photo .gif-photo-loading .path{stroke-dasharray:1,200;stroke-dashoffset:0;stroke:#ccc;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}.m-photo .s-tip{background:#fff;border:1px solid #f5f7f9;-webkit-box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);color:#333;font-size:.37333rem;height:1.25333rem;letter-spacing:0;line-height:1.25333rem;text-align:center}.m-photo .s-tip .icon-arrow{font-size:.26667rem}.m-photo .s-wrap{overflow:hidden;position:relative;text-align:center}.m-photo img{background:#e5e5e5 url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/bg.2256edadd69b78418e29.png) 50%/3.6rem 2.69333rem no-repeat;min-height:4.13333rem;-o-object-fit:contain;object-fit:contain;width:100%}.m-photo figcaption{color:#999;font-size:.37333rem;margin:.21333rem 0 0;padding:0 0 0 .34667rem;position:relative}.m-photo figcaption .icon-quotes-left{font-size:.21333rem;left:0;position:absolute;top:.21333rem}.photoPreview{background:#000;height:100%;left:0;position:fixed;top:0;width:100%;z-index:99999}.photoPreview.hide{display:none}.photoPreview .swiper-slide{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;justify-content:center;overflow:hidden;width:100%}.photoPreview .swiper-slide img{max-height:100%;max-width:100%}.photoPreview .swiper-pagination{bottom:.13333rem;color:#b4b4b4;font-size:.42667rem;font-weight:500;left:.26667rem;margin:0;position:absolute;z-index:10}.photoPreview .swiper-pagination .swiper-pagination-current{color:#ee1a1a;font-size:.74667rem}.photoPreview .s-close{height:.66667rem;left:.06667rem;position:absolute;top:.06667rem;width:.66667rem;z-index:50}.photoPreview .s-close:after,.photoPreview .s-close:before{background:#b4b4b4;content:"";height:.04rem;left:.13333rem;position:absolute;top:.29333rem;width:.4rem}.photoPreview .s-close:before{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.photoPreview .s-close:after{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.m-photoSet{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:center;margin:.66667rem auto .77333rem;width:100%}.m-photoSet .s-tip{background:#fff;border:1px solid #f5f7f9;-webkit-box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);color:#333;font-size:.37333rem;height:1.25333rem;letter-spacing:0;line-height:1.25333rem;text-align:center}.m-photoSet .s-tip .icon-arrow{font-size:.26667rem}.m-photoSet .s-wrap{overflow:hidden;position:relative}.m-photoSet .s-tag{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:rgba(0,0,0,.6);border-radius:.34667rem;bottom:.21333rem;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.32rem;font-weight:500;height:.69333rem;line-height:.69333rem;padding:0 .32rem;position:absolute;right:.21333rem;z-index:5}.m-photoSet .s-tag:before{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/photo.7577501b5095467d8ff1.png) 50% no-repeat;background-size:100% 100%;content:"";height:.32rem;margin:0 .09333rem 0 0;width:.32rem}.m-photoSet img{background:#e5e5e5 url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/bg.2256edadd69b78418e29.png) 50%/3.6rem 2.69333rem no-repeat;min-height:4.13333rem;-o-object-fit:contain;object-fit:contain;width:100%}.m-photoSet figcaption{color:#999;font-size:.37333rem;margin:.21333rem 0 0;padding:0 0 0 .34667rem;position:relative}.m-photoSet figcaption .icon-quotes-left{font-size:.21333rem;left:0;position:absolute;top:.21333rem}.m-audio{margin:0;padding:0;text-align:center}.m-audio figcaption{color:#999;font-size:.37333rem;margin:.21333rem 0 1.06667rem;text-align:center}.m-video{text-align:center;width:100%}.m-video,.m-video figure{margin:0;padding:0}.m-video .s-wrap{background:#000;overflow:hidden;position:relative;text-align:center;width:100%}.m-video .s-cover{height:100%;left:0;position:absolute;top:0;width:100%;z-index:10}.m-video .s-cover.hide{display:none}.m-video .s-cover img{background:#e5e5e5 url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/bg.2256edadd69b78418e29.png) 50%/3.6rem 2.69333rem no-repeat;height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.m-video .s-cover .icon-play{background-color:hsla(0,0%,100%,.9);border-radius:50%;color:#333;font-size:.45333rem;height:1.28rem;left:50%;line-height:1.28rem;position:absolute;text-align:center;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:1.28rem}.m-video .s-video video{max-height:670PX;width:100%}.m-video figcaption{color:#999;font-size:.37333rem;margin:.21333rem 0 1.06667rem;padding:0 0 0 .34667rem;position:relative;text-align:left}.m-video figcaption .icon-quotes-left{font-size:.21333rem;left:0;position:absolute;top:.21333rem}.m-video .s-tip{background:#fff;border:1px solid #f5f7f9;-webkit-box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);box-shadow:0 .02667rem .02667rem 0 rgba(0,0,0,.05);color:#333;font-size:.37333rem;height:1.25333rem;letter-spacing:0;line-height:1.25333rem;text-align:center}.m-video .s-tip .icon-arrow{font-size:.26667rem}.m-timeline header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.45333rem;font-weight:500;line-height:.66667rem}.m-timeline header .icon-timeline{font-size:.4rem;margin:0 .13333rem 0 0}.m-timeline ul{list-style:none;margin:.4rem 0 0;padding:0 0 0 .06667rem}.m-timeline ul li{position:relative}.m-timeline ul li:before{background:#eee;content:"";height:100%;left:.06667rem;position:absolute;top:.46667rem;width:.02667rem}.m-timeline ul li:last-child:before{display:none}.m-timeline .s-time{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#ee1a1a;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.37333rem;line-height:.77333rem}.m-timeline .s-time:before{background:#fff;border:.02667rem solid #ee1a1a;border-radius:50%;content:"";height:.16rem;margin:0 .32rem 0 0;width:.16rem}.m-timeline .s-event{color:#666;font-size:.42667rem;font-weight:400;line-height:.66667rem;margin:0 0 0 .48rem}.m-spinfo{margin:.66667rem 0 .4rem}.m-spinfo .s-type{color:#333;font-size:.45333rem;font-weight:500;line-height:.66667rem;margin:0 0 .4rem}.m-spinfo .s-type:before{background:url(https://static.ws.126.net/163/frontend/backflow-ssr/combined.svg) 50% no-repeat;background-size:100% 100%;content:"";display:inline-block;height:.29333rem;margin:0 .18667rem 0 0;width:.21333rem}.m-spinfo .s-content{color:#666;font-size:.42667rem;line-height:.66667rem}.m-linkCard{margin:.4rem 0}.m-linkCard a{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#fcfcfc;border:1px solid #ddd;border-radius:.05333rem;color:#999;padding:.29333rem .4rem .29333rem .29333rem}.m-linkCard .s-info,.m-linkCard a{display:-webkit-box;display:-ms-flexbox;display:flex}.m-linkCard .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-flex:1;-ms-flex-positive:1;-ms-flex-direction:column;flex-direction:column;flex-grow:1;margin:0 .4rem;overflow:hidden}.m-linkCard .s-info h3{color:#333;font-size:.48rem;line-height:.66667rem;margin:0}.m-linkCard .s-info h3,.m-linkCard .s-info small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.m-linkCard .s-info small{color:#999;font-size:.34667rem}.m-linkCard .s-img{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;align-items:center;border-radius:.06667rem;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;height:1.46667rem;justify-content:center;overflow:hidden;width:1.46667rem}.m-linkCard .s-img img{height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.m-linkCard .icon-arrow{-ms-flex-negative:0;flex-shrink:0}.m-link{color:#1b88ee}.m-liveCard{margin:.4rem 0}.m-liveCard a{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:#f5f7f9;border-radius:.05333rem;color:#999;padding:.29333rem .4rem .29333rem .29333rem}.m-liveCard .s-info,.m-liveCard a{display:-webkit-box;display:-ms-flexbox;display:flex}.m-liveCard .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-flex:1;-ms-flex-positive:1;-ms-flex-direction:column;flex-direction:column;flex-grow:1;margin:0 .4rem;overflow:hidden}.m-liveCard .s-info h3{color:#333;font-size:.48rem;font-weight:400;line-height:.66667rem;margin:0}.m-liveCard .s-info h3,.m-liveCard .s-info small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.m-liveCard .s-info small{color:#999;font-size:.34667rem}.m-liveCard .s-img{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;-ms-flex-negative:0;align-items:center;border-radius:.06667rem;display:-webkit-box;display:-ms-flexbox;display:flex;flex-shrink:0;height:1.46667rem;justify-content:center;overflow:hidden;width:1.46667rem}.m-liveCard .s-img img{height:100%;-o-object-fit:cover;object-fit:cover;width:100%}.m-variousTalks .s-header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#667c89;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;line-height:.53333rem;padding:.42667rem 0 .58667rem}.m-variousTalks .s-header .icon-talk{margin:0 .06667rem 0 0}.m-variousTalks ul{list-style:none;margin:0;padding:0 0 0 .13333rem}.m-variousTalks ul li{display:-webkit-box;display:-ms-flexbox;display:flex;margin:.10667rem 0}.m-variousTalks .s-avatar{-ms-flex-negative:0;border-radius:50%;flex-shrink:0;height:.85333rem;margin:0 .13333rem 0 0;overflow:hidden;width:.85333rem}.m-variousTalks .s-avatar img{height:100%;width:100%}.m-variousTalks .s-info{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden}.m-variousTalks .s-info .s-blue{color:#5da4ef}.m-variousTalks .s-info .s-red{color:#e15241}.m-variousTalks .s-info .s-name{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#666;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.42667rem;line-height:.6rem;overflow:hidden}.m-variousTalks .s-info .s-name span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.m-variousTalks .s-info .s-name .icon-flag{-ms-flex-negative:0;flex-shrink:0;font-size:.32rem;margin:0 0 0 .26667rem}.m-variousTalks .s-info .s-talk{color:#333;font-size:.42667rem;line-height:.6rem}.m-pk{-webkit-box-orient:vertical;-webkit-box-direction:normal;border:1px solid #ddd;border-radius:.08rem;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:.29333rem .4rem}.m-pk .s-title{color:#333;font-size:.45333rem;font-weight:400;line-height:.6rem;margin:0}.m-pk .s-opinions{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#555;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.37333rem;justify-content:space-between;line-height:.6rem;margin:.29333rem 0}.m-pk .s-opinion{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;width:3.46667rem}.m-pk .s-opinion .s-blueFlag,.m-pk .s-opinion .s-redFlag{border-radius:.08rem;font-size:.29333rem;font-weight:500;line-height:.4rem;margin:0 .13333rem 0 0;padding:0 .10667rem}.m-pk .s-opinion .s-redFlag{background:rgba(238,26,26,.1);color:#ee1a1a}.m-pk .s-opinion .s-blueFlag{background:rgba(27,136,238,.1);color:#1b88ee}.m-pk .s-s,.m-pk .s-v{font-size:.66667rem;font-weight:600}.m-pk .s-v{color:#ee1a1a;margin:0 0 0 .29333rem}.m-pk .s-s{color:#1b88ee;margin:0 .29333rem 0 0}.m-pk .s-votes{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin:0 0 .4rem}.m-pk .s-vote-blue,.m-pk .s-vote-red,.m-pk .s-votes{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.m-pk .s-vote-blue,.m-pk .s-vote-red{-webkit-box-pack:center;-ms-flex-pack:center;border-radius:50%;font-size:0;height:1.17333rem;justify-content:center;width:1.17333rem}.m-pk .s-vote-blue:before,.m-pk .s-vote-red:before{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/pk-like.d2c827658dc0eaedb848.png) 50% no-repeat;background-size:100% 100%;content:"";height:.53333rem;margin:0 0 .06667rem;width:.53333rem}.m-pk .s-vote-red{background-image:-webkit-gradient(linear,left top,left bottom,from(#f77),to(#ee1a1a));background-image:linear-gradient(180deg,#f77,#ee1a1a)}.m-pk .s-vote-blue{background-image:-webkit-gradient(linear,left top,left bottom,from(#50c8ff),to(#1b88ee));background-image:linear-gradient(180deg,#50c8ff,#1b88ee)}.m-pk .s-vote-blue:before{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.m-pk .s-progress{-webkit-box-flex:1;-ms-flex-positive:1;display:-webkit-box;display:-ms-flexbox;display:flex;flex-grow:1;height:.16rem;margin:0 .16rem}.m-pk .s-num{font-size:.37333rem;font-weight:500;line-height:.50667rem;position:absolute;top:.16rem}.m-pk .s-red-progress{background:#ee1a1a;border-radius:.08rem 0 0 .08rem;margin:0 .04rem 0 0;position:relative;width:30%}.m-pk .s-red-progress .s-num{color:#ee1a1a;left:0}.m-pk .s-blue-progress{-webkit-box-flex:1;-ms-flex-positive:1;background:#1b88ee;border-radius:0 .08rem .08rem 0;flex-grow:1;margin:0 0 0 .04rem;position:relative}.m-pk .s-blue-progress .s-num{color:#1b88ee;right:0}.m-pk .s-info{color:#999;font-size:.32rem}.m-vote{-webkit-box-orient:vertical;-webkit-box-direction:normal;border:1px solid #ddd;border-radius:.08rem;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:.29333rem .4rem}.m-vote.m-voted .s-input{display:none}.m-vote.m-voted .s-num{display:-webkit-box;display:-ms-flexbox;display:flex}.m-vote.m-voted .s-form-item.s-selected{background:#eee}.m-vote.m-voted .s-submit{display:none}.m-vote .s-title{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.45333rem;font-weight:400;line-height:1.5;margin:0}.m-vote .s-type{background:#ee1a1a;border-radius:.08rem;color:#fff;font-size:.29333rem;font-weight:400;line-height:.4rem;margin:0 .06667rem 0 0;padding:0 .10667rem}.m-vote .s-form{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.m-vote .s-form,.m-vote .s-form-item{display:-webkit-box;display:-ms-flexbox;display:flex}.m-vote .s-form-item{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #eee;border-radius:.13333rem;color:#333;justify-content:space-between;margin:.13333rem 0;padding:.13333rem}.m-vote .s-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#fff;border:.02667rem solid #333;border-radius:50%;height:.32rem;line-height:.8rem;margin:.12rem;width:.32rem}.m-vote .s-content{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;font-size:.37333rem;line-height:1.5;margin:0 .66667rem 0 .16rem;text-align:left}.m-vote .s-num{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-negative:0;color:#666;display:none;-ms-flex-direction:column;flex-direction:column;flex-shrink:0;font-size:.29333rem;line-height:1.5;text-align:right}.m-vote .s-submit{background:#ee1a1a;border:none;border-radius:1.33333rem;color:#fff;font-size:.4rem;height:.88rem;margin:.4rem auto 0;text-align:center;width:3.2rem}.m-vote .s-info{color:#999;font-size:.32rem}.operate{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;margin:1.06667rem 0 .8rem}.operate,.operate .operate-share{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.operate .operate-share{-webkit-box-orient:vertical;-webkit-box-direction:normal;color:#666;-ms-flex-direction:column;flex-direction:column;font-size:.37333rem}.operate .operate-share .share-icon{background:#f5f7f9 url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/share.1b731a80ed582f2a26df.png) 50% no-repeat;background-size:.74667rem .74667rem;border-radius:50%;height:1.6rem;margin:0 0 .22667rem;width:1.6rem}.backflow-floating{-webkit-box-align:center;-ms-flex-align:center;-webkit-box-pack:center;-ms-flex-pack:center;align-items:center;background:#ee1a1a;border-radius:.58667rem;bottom:1.22667rem;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.45333rem;height:1.17333rem;justify-content:center;left:50%;padding:0 .64rem;position:fixed;-webkit-transform:translate(-50%);transform:translate(-50%);z-index:999}.backflow-floating i{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/logo-small.6a69e71772d6dd5466da.png) 50% no-repeat;background-size:100% 100%;display:block;height:.53333rem;margin-right:.16rem;width:.53333rem}.m_clearfix{clear:both;overflow:hidden}.m_a_d_logo{background:url(https://static.ws.126.net/163/frontend/images/ad-logo-0817.png);background-size:100%;bottom:.15rem;height:.23rem;position:absolute;right:.1rem;width:.4rem}.papa-item{position:relative}.papa-item .papa_flag{background:rgba(0,0,0,.5);border-top-right-radius:.15rem;bottom:.2rem;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;font-size:.24rem;left:0;padding:1px 6px 1px 2px;position:absolute;text-align:center}.m_papa{font-size:.24rem}.m_papa.s-empty{padding:0}.m_papa .m_papa_img{float:left;height:1.46rem;margin-right:.2rem;overflow:hidden;position:relative;width:2.34rem}.m_papa .m_papa_img img{background:none;display:block;height:100%;-o-object-fit:contain;object-fit:contain;width:100%}.m_papa .m_papa_desc .m_papa_promote{font-size:12px;height:12px;line-height:12px;padding:2px}.m_papa .m_papa_desc .m_papa_time{color:#888;display:inline-block;font-size:.24rem;margin-left:.2rem}.m_papa .m_papa_desc .m_papa_desc_l{float:left}.m_papa .m_papa_info{overflow:hidden}.m_papa .m_papa_info .m_papa_title,.m_papa .m_papa_info a{color:#404040;font-size:.34rem;line-height:.42rem;margin-bottom:.2rem;text-decoration:none}.m_papa_m0 .m_papa_title{color:#404040;font-size:.34rem;margin-bottom:.2rem}.m_papa_m0 .m_papa_img{height:3.45rem;width:100%}.m_papa_m0 .m_papa_promote{border:1px solid #555;border-radius:3px;color:#555;float:right;font-size:.24rem;height:.32rem;line-height:.32rem;padding:2px}.m_papa_m1 .m_papa_title{color:#404040;font-size:.34rem;margin-bottom:.2rem}.m_papa_m1 .m_papa_title .m_papa_promote{border:1px solid #555;float:right;font-size:.24rem;height:12px;line-height:12px;padding:2px}.m_papa_m1 .m_papa_pic{display:block;margin:.22rem 0}.m_papa_m1 .m_papa_pic .m_papa_pic_wrap{-webkit-box-pack:justify;-ms-flex-pack:justify;height:1.46rem;justify-content:space-between;overflow:hidden}.m_papa_m1 .m_papa_pic .m_papa_pic_wrap img{float:left;height:100%;margin-right:1px;-o-object-fit:contain;object-fit:contain;width:33%}.m_papa_m2{background:#eee;border-top:1px solid #e5e5e5;margin:-1px 0 0;width:100%}.m_papa_m2 .m_papa_content{color:#4c9aea;font-size:.34rem}.m_papa_m2 .m_papa_content a,.m_papa_m2 .m_papa_content a:active,.m_papa_m2 .m_papa_content a:focus,.m_papa_m2 .m_papa_content a:visited{color:#4c9aea}.m_papa_m2 .m_papa_promote{border:1px solid #555;float:right;font-size:12px;height:12px;line-height:12px;padding:2px}.m_papa_live .m_papa_img{height:3.45rem}.m_papa_iframe .m_papa_iframe_wrap{height:1.4rem;overflow:hidden;width:6.9rem}.m_papa_iframe iframe{height:100%;width:100%}.m_papa_iframe_photoset .m_papa_iframe_wrap{height:2.44rem;overflow:hidden;width:6.9rem}.m_papa_iframe_photoset iframe{height:100%;width:100%}.m_photoset_square{background:#fff;border:0;-webkit-box-shadow:0 1px 1px #e3e3e3;box-shadow:0 1px 1px #e3e3e3;float:left;margin:.2rem 0 0;padding:0;width:3.35rem}.m_photoset_square .m_photoset_square_img{-webkit-animation:imgload2 1s ease-out;animation:imgload2 1s ease-out;-webkit-animation-duration:1s;-webkit-animation-name:imgload2;-webkit-animation-timing-function:ease-out;float:left;height:auto;overflow:hidden;position:relative;width:100%}.m_photoset_square .m_photoset_square_img img{display:block;min-height:2rem;width:100%}.m_photoset_square.papa_item .m_photoset_square_info .m_photoset_square_title span{display:inline}.m_photoset_square.papa_item .m_photoset_square_info .m_photoset_square_title .m_photoset_square_adflag{background-size:100% 100%;color:#efd469;display:inline-block;font-size:12px;line-height:12px;margin-right:.1rem;padding:2px}.m_photoset_square .m_photoset_square_info{-webkit-box-sizing:border-box;box-sizing:border-box;float:left;padding:.15rem;width:100%}.m_photoset_square .m_photoset_square_info .m_photoset_square_title{color:#555;margin-bottom:.15rem;width:100%}.m_photoset_square .m_photoset_square_info .m_photoset_square_title span{display:block;font-size:.28rem;line-height:.42rem}.m_photoset_square .m_photoset_square_info .m_photoset_square_desc{width:100%}.m_photoset_square .m_photoset_square_info .m_photoset_square_desc .m_photoset_square_desc_l{background-position:left 0;background-repeat:no-repeat;background-size:contain;color:#888;float:left;font-size:.24rem;line-height:.36rem}.m_photoset_square .m_photoset_square_info .m_photoset_square_desc .m_photoset_square_desc_l .iconfont{color:#a8a8a8;display:inline-block;font-size:.28rem;padding:0 .1rem 0 0}.m_photoset_square .m_photoset_square_info .m_photoset_square_desc .m_photoset_square_desc_r{background-position:left 0;background-repeat:no-repeat;background-size:contain;color:#888;float:right;font-size:.24rem;line-height:.36rem}.m_photoset_square .m_photoset_square_info .m_photoset_square_desc .m_photoset_square_desc_r .iconfont{color:#a8a8a8;display:inline-block;font-size:.28rem;padding:0 .1rem 0 0}.m_papa_m2{border-top:0}.m_papa_m2.m_papa{border-bottom:0;padding:0}.m_papa_m2 .m_papa_promote{background-size:100% 100%;border:none;border-radius:3px;color:#555;display:inline-block;font-size:.26rem;height:.37rem;line-height:.37rem;padding:.03rem;position:absolute;right:.3rem;top:.2rem}.m_papa_m1 .m_papa_title,.m_papa_m2 .m_papa_content{line-height:.44rem;width:6.2rem}.m_papa_m1 .m_papa_title .m_papa_promote{border:none;border-radius:3px;position:absolute;right:0;top:.2rem}.m_papa .m_papa_desc .m_papa_promote,.m_papa_m1 .m_papa_title .m_papa_promote{background-size:100% 100%;color:#555;display:inline-block;font-size:.26rem;height:.37rem;line-height:.37rem;padding:.03rem}.m_papa .m_papa_desc .m_papa_promote{border:none}.m_colum_a_d{font-size:.24rem;position:relative}.m_colum_a_d.s_empty{padding:0}.m_colum_a_d .s_img{float:left;margin-right:.2rem;max-height:5.45rem;overflow:hidden;position:relative;width:100%}.m_colum_a_d .s_img img{background:none;display:block;height:100%;-o-object-fit:contain;object-fit:contain;width:100%}.m_colum_a_d .s_title{color:#404040;font-size:.34rem;margin-bottom:.2rem}.m_colum_a_d .m_a_d_source{bottom:.15rem;color:#a3a3a3;font-size:.24rem;position:absolute;right:.1rem}.m_a_d_doc .m_papa_img{float:right;margin-left:.4rem;margin-right:0}.m_a_d_doc .m_a_d_logo{bottom:.1rem;left:.1rem;right:auto}.m_a_d_doc .m_papa_info{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:justify;-ms-flex-pack:justify;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:space-between}.m-ltrp{font-size:.24rem;overflow:hidden}.m-ltrp a{color:#333}.m-ltrp .m-ltrp-title{float:left;max-width:40%;min-height:1rem;width:40%}.m-ltrp .m-ltrp-title .s-title{-webkit-box-orient:vertical;-webkit-line-clamp:2;height:.7rem;margin:1px 0 0 3px;overflow:hidden;text-overflow:ellipsis}.m-ltrp .m-ltrp-title .s-source{bottom:1px;color:#999;font-size:.2rem;left:1px;line-height:.28rem;position:absolute}.m-ltrp .m-ltrp-title .s-promote{border:1px solid #999;border-radius:5px;display:inline-block;margin-right:5px;padding:0 5px;-webkit-transform:scale(.8);transform:scale(.8)}.m-ltrp .m-ltrp-img{-webkit-box-align:center;-ms-flex-align:center;-webkit-box-pack:justify;-ms-flex-pack:justify;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;float:right;font-size:0;justify-content:space-between;width:60%}.m-ltrp .m-ltrp-img img{display:inline-block;width:33%}.m_a_d_card{-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#fcfcfc;border:1px solid #ddd;border-radius:.04rem;display:-webkit-box;display:-ms-flexbox;display:flex;font-family:-apple-system,Hiragino Sans GB,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;padding:.22rem .48rem .23rem .32rem}.m_a_d_card .info{-webkit-box-flex:1;-ms-flex-positive:1;color:#999;flex-grow:1;margin-right:.4rem;width:4.17rem}.m_a_d_card .info,.m_a_d_card .info h3{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.m_a_d_card .info h3{color:#333;font-size:.32rem;line-height:.5rem;margin:.1rem 0 .04rem}.m_a_d_card .info small{font-size:.26rem;line-height:.37rem;max-width:100%}.m_a_d_card .icon-arrow{background:url(https://static.ws.126.net/163/frontend/images/arrow-hdbk.png) no-repeat;background-size:100%;color:#999;font-size:.19rem;height:.3rem;width:.3rem}.m_a_d_card .icon-arrow,.m_a_d_card_img{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.m_a_d_card_img{-webkit-box-pack:center;-ms-flex-pack:center;-ms-flex-negative:0;flex-shrink:0;height:1.1rem;justify-content:center;margin-right:.34rem;width:1.1rem}.m_a_d_card_img img{border-radius:.08rem;height:100%;vertical-align:top;width:100%}@font-face{font-family:swiper-icons;font-style:normal;font-weight:400;src:url("data:application/font-woff;charset=utf-8;base64, d09GRgABAAAAAAZgABAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAGRAAAABoAAAAci6qHkUdERUYAAAWgAAAAIwAAACQAYABXR1BPUwAABhQAAAAuAAAANuAY7+xHU1VCAAAFxAAAAFAAAABm2fPczU9TLzIAAAHcAAAASgAAAGBP9V5RY21hcAAAAkQAAACIAAABYt6F0cBjdnQgAAACzAAAAAQAAAAEABEBRGdhc3AAAAWYAAAACAAAAAj//wADZ2x5ZgAAAywAAADMAAAD2MHtryVoZWFkAAABbAAAADAAAAA2E2+eoWhoZWEAAAGcAAAAHwAAACQC9gDzaG10eAAAAigAAAAZAAAArgJkABFsb2NhAAAC0AAAAFoAAABaFQAUGG1heHAAAAG8AAAAHwAAACAAcABAbmFtZQAAA/gAAAE5AAACXvFdBwlwb3N0AAAFNAAAAGIAAACE5s74hXjaY2BkYGAAYpf5Hu/j+W2+MnAzMYDAzaX6QjD6/4//Bxj5GA8AuRwMYGkAPywL13jaY2BkYGA88P8Agx4j+/8fQDYfA1AEBWgDAIB2BOoAeNpjYGRgYNBh4GdgYgABEMnIABJzYNADCQAACWgAsQB42mNgYfzCOIGBlYGB0YcxjYGBwR1Kf2WQZGhhYGBiYGVmgAFGBiQQkOaawtDAoMBQxXjg/wEGPcYDDA4wNUA2CCgwsAAAO4EL6gAAeNpj2M0gyAACqxgGNWBkZ2D4/wMA+xkDdgAAAHjaY2BgYGaAYBkGRgYQiAHyGMF8FgYHIM3DwMHABGQrMOgyWDLEM1T9/w8UBfEMgLzE////P/5//f/V/xv+r4eaAAeMbAxwIUYmIMHEgKYAYjUcsDAwsLKxc3BycfPw8jEQA/gZBASFhEVExcQlJKWkZWTl5BUUlZRVVNXUNTQZBgMAAMR+E+gAEQFEAAAAKgAqACoANAA+AEgAUgBcAGYAcAB6AIQAjgCYAKIArAC2AMAAygDUAN4A6ADyAPwBBgEQARoBJAEuATgBQgFMAVYBYAFqAXQBfgGIAZIBnAGmAbIBzgHsAAB42u2NMQ6CUAyGW568x9AneYYgm4MJbhKFaExIOAVX8ApewSt4Bic4AfeAid3VOBixDxfPYEza5O+Xfi04YADggiUIULCuEJK8VhO4bSvpdnktHI5QCYtdi2sl8ZnXaHlqUrNKzdKcT8cjlq+rwZSvIVczNiezsfnP/uznmfPFBNODM2K7MTQ45YEAZqGP81AmGGcF3iPqOop0r1SPTaTbVkfUe4HXj97wYE+yNwWYxwWu4v1ugWHgo3S1XdZEVqWM7ET0cfnLGxWfkgR42o2PvWrDMBSFj/IHLaF0zKjRgdiVMwScNRAoWUoH78Y2icB/yIY09An6AH2Bdu/UB+yxopYshQiEvnvu0dURgDt8QeC8PDw7Fpji3fEA4z/PEJ6YOB5hKh4dj3EvXhxPqH/SKUY3rJ7srZ4FZnh1PMAtPhwP6fl2PMJMPDgeQ4rY8YT6Gzao0eAEA409DuggmTnFnOcSCiEiLMgxCiTI6Cq5DZUd3Qmp10vO0LaLTd2cjN4fOumlc7lUYbSQcZFkutRG7g6JKZKy0RmdLY680CDnEJ+UMkpFFe1RN7nxdVpXrC4aTtnaurOnYercZg2YVmLN/d/gczfEimrE/fs/bOuq29Zmn8tloORaXgZgGa78yO9/cnXm2BpaGvq25Dv9S4E9+5SIc9PqupJKhYFSSl47+Qcr1mYNAAAAeNptw0cKwkAAAMDZJA8Q7OUJvkLsPfZ6zFVERPy8qHh2YER+3i/BP83vIBLLySsoKimrqKqpa2hp6+jq6RsYGhmbmJqZSy0sraxtbO3sHRydnEMU4uR6yx7JJXveP7WrDycAAAAAAAH//wACeNpjYGRgYOABYhkgZgJCZgZNBkYGLQZtIJsFLMYAAAw3ALgAeNolizEKgDAQBCchRbC2sFER0YD6qVQiBCv/H9ezGI6Z5XBAw8CBK/m5iQQVauVbXLnOrMZv2oLdKFa8Pjuru2hJzGabmOSLzNMzvutpB3N42mNgZGBg4GKQYzBhYMxJLMlj4GBgAYow/P/PAJJhLM6sSoWKfWCAAwDAjgbRAAB42mNgYGBkAIIbCZo5IPrmUn0hGA0AO8EFTQAA") format("woff")}:root{--swiper-theme-color:#007aff}.swiper{list-style:none;margin-left:auto;margin-right:auto;overflow:hidden;padding:0;position:relative;z-index:1}.swiper-vertical>.swiper-wrapper{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.swiper-wrapper{-webkit-box-sizing:content-box;box-sizing:content-box;display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;position:relative;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;width:100%;z-index:1}.swiper-android .swiper-slide,.swiper-wrapper{-webkit-transform:translateZ(0);transform:translateZ(0)}.swiper-pointer-events{-ms-touch-action:pan-y;touch-action:pan-y}.swiper-pointer-events.swiper-vertical{-ms-touch-action:pan-x;touch-action:pan-x}.swiper-slide{-ms-flex-negative:0;flex-shrink:0;height:100%;position:relative;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;width:100%}.swiper-slide-invisible-blank{visibility:hidden}.swiper-autoheight,.swiper-autoheight .swiper-slide{height:auto}.swiper-autoheight .swiper-wrapper{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-webkit-transition-property:height,-webkit-transform;transition-property:height,-webkit-transform;transition-property:transform,height;transition-property:transform,height,-webkit-transform}.swiper-backface-hidden .swiper-slide{-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0)}.swiper-3d,.swiper-3d.swiper-css-mode .swiper-wrapper{-webkit-perspective:1200px;perspective:1200px}.swiper-3d .swiper-cube-shadow,.swiper-3d .swiper-slide,.swiper-3d .swiper-slide-shadow,.swiper-3d .swiper-slide-shadow-bottom,.swiper-3d .swiper-slide-shadow-left,.swiper-3d .swiper-slide-shadow-right,.swiper-3d .swiper-slide-shadow-top,.swiper-3d .swiper-wrapper{-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.swiper-3d .swiper-slide-shadow,.swiper-3d .swiper-slide-shadow-bottom,.swiper-3d .swiper-slide-shadow-left,.swiper-3d .swiper-slide-shadow-right,.swiper-3d .swiper-slide-shadow-top{height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:10}.swiper-3d .swiper-slide-shadow{background:rgba(0,0,0,.15)}.swiper-3d .swiper-slide-shadow-left{background-image:-webkit-gradient(linear,right top,left top,from(rgba(0,0,0,.5)),to(transparent));background-image:linear-gradient(270deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-right{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(transparent));background-image:linear-gradient(90deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-top{background-image:-webkit-gradient(linear,left bottom,left top,from(rgba(0,0,0,.5)),to(transparent));background-image:linear-gradient(0deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-bottom{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.5)),to(transparent));background-image:linear-gradient(180deg,rgba(0,0,0,.5),transparent)}.swiper-css-mode>.swiper-wrapper{-ms-overflow-style:none;overflow:auto;scrollbar-width:none}.swiper-css-mode>.swiper-wrapper::-webkit-scrollbar{display:none}.swiper-css-mode>.swiper-wrapper>.swiper-slide{scroll-snap-align:start start}.swiper-horizontal.swiper-css-mode>.swiper-wrapper{-webkit-scroll-snap-type:x mandatory;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory}.swiper-vertical.swiper-css-mode>.swiper-wrapper{-webkit-scroll-snap-type:y mandatory;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory}.swiper-centered>.swiper-wrapper:before{-ms-flex-negative:0;-webkit-box-ordinal-group:10000;-ms-flex-order:9999;content:"";flex-shrink:0;order:9999}.swiper-centered.swiper-horizontal>.swiper-wrapper>.swiper-slide:first-child{-webkit-margin-start:var(--swiper-centered-offset-before);margin-inline-start:var(--swiper-centered-offset-before)}.swiper-centered.swiper-horizontal>.swiper-wrapper:before{height:100%;width:var(--swiper-centered-offset-after)}.swiper-centered.swiper-vertical>.swiper-wrapper>.swiper-slide:first-child{-webkit-margin-before:var(--swiper-centered-offset-before);margin-block-start:var(--swiper-centered-offset-before)}.swiper-centered.swiper-vertical>.swiper-wrapper:before{height:var(--swiper-centered-offset-after);width:100%}.swiper-centered>.swiper-wrapper>.swiper-slide{scroll-snap-align:center center}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px} /*! Theme: GitHub Description: Light theme as seen on github.com Author: github.com Maintainer: @Hirse Updated: 2021-05-15 Outdated base version: https://github.com/primer/github-syntax-light Current colors taken from GitHub's CSS */.hljs{background:#fff;color:#24292e}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{background-color:#f0fff4;color:#22863a}.hljs-deletion{background-color:#ffeef0;color:#b31d28}.login-wrap{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:rgba(0,0,0,.5);bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;left:0;margin:auto;position:fixed;right:0;top:0;visibility:hidden;z-index:1999}.login-wrap.login-dialog-show{visibility:visible}.login-wrap.login-dialog-forceLogin .login-close{display:none}.login-wrap .login-title{color:#333;font-size:.37333rem;margin:0 0 .26667rem;text-align:center}.login-wrap .login-title strong{font-size:.42667rem}.login-wrap .login-module{background-color:#fff;border-radius:.4rem;max-width:300PX;min-height:6.66667rem;overflow:hidden;padding:20PX 20PX 10PX;position:relative;width:80%}.login-wrap .login-close{color:#666;font-size:.32rem;font-weight:600;padding:.26667rem;position:absolute;z-index:10}.dialog-alert,.login-wrap .login-close{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;right:0;top:0}.dialog-alert{background:rgba(0,0,0,.5);bottom:0;left:0;margin:auto;position:fixed;z-index:1499}.dialog-alert .alert-content{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:#fff;border-radius:.42667rem;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden;width:8rem}.dialog-alert .alert-content .s-title{color:#333;font-size:.48rem;font-weight:600;margin:.97333rem .53333rem .4rem;text-align:center}.dialog-alert .alert-content .s-subTitle{color:#555;font-size:.42667rem;margin:0 .53333rem .4rem;text-align:center}.dialog-alert .alert-content .s-btn{background:#e64646;border-radius:.46667rem;color:#fff;font-size:.42667rem;height:.93333rem;line-height:.93333rem;margin:.26667rem 0 .4rem;max-width:6.93333rem;min-width:4.8rem;overflow:hidden;padding:0 .26667rem;text-align:center;text-overflow:ellipsis;white-space:nowrap}.dialog-confirm{-webkit-box-pack:center;-ms-flex-pack:center;background:rgba(0,0,0,.5);bottom:0;justify-content:center;left:0;margin:auto;position:fixed;right:0;top:0;z-index:1499}.dialog-confirm,.dialog-confirm .confirm-content{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex}.dialog-confirm .confirm-content{-webkit-box-orient:vertical;-webkit-box-direction:normal;background:#fff;border-radius:.42667rem;-ms-flex-direction:column;flex-direction:column;overflow:hidden;width:8rem}.dialog-confirm .confirm-content .s-title{color:#333;font-size:.48rem;font-weight:600;margin:.97333rem .53333rem .4rem;text-align:center}.dialog-confirm .confirm-content .s-subTitle{color:#555;font-size:.42667rem;margin:0 .53333rem .4rem;text-align:center}.dialog-confirm .confirm-content .s-btns{display:-webkit-box;display:-ms-flexbox;display:flex;margin:.26667rem 0 .66667rem}.dialog-confirm .confirm-content .s-btn{background:#e64646;border-radius:.46667rem;color:#fff;font-size:.42667rem;height:.93333rem;line-height:.93333rem;margin:0 .26667rem;min-width:2.66667rem;overflow:hidden;padding:0 .26667rem;text-align:center;text-overflow:ellipsis;white-space:nowrap}.dialog-confirm .confirm-content .s-btn.s-btn-2{background:#f5f7f9;color:#333}.login-drawer-wrap{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:rgba(0,0,0,.5);bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;left:0;margin:auto;max-width:750PX;position:fixed;right:0;top:0;visibility:hidden;z-index:1999}.login-drawer-wrap.login-drawer-show{visibility:visible}.login-drawer-wrap.login-drawer-show .login-drawer{-webkit-transform:translateX(0);transform:translateX(0)}.login-drawer-wrap .login-drawer{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:justify;-ms-flex-pack:justify;background:#fff;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:space-between;left:0;max-width:300PX;position:absolute;top:0;-webkit-transform:translateX(-100%);transform:translateX(-100%);-webkit-transition:-webkit-transform .3s linear;transition:-webkit-transform .3s linear;transition:transform .3s linear;transition:transform .3s linear,-webkit-transform .3s linear;width:75%}.login-drawer-wrap .s-holder{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.login-drawer-wrap .s-feedback{-webkit-box-pack:center;-ms-flex-pack:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#333;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;justify-content:center;margin:0 0 .26667rem}.login-drawer-wrap .s-feedback:before{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/feedback.79a4273c047bba72e222.png) 50% no-repeat;background-size:100% 100%;content:"";height:.64rem;margin:0 .06667rem 0 0;width:.64rem}.login-drawer-wrap .s-distribution{-ms-flex-item-align:center;align-self:center;margin:0 0 .26667rem;width:90%}.login-drawer-wrap .s-distribution img{width:100%}.login-drawer-wrap .login-drawer-module{background-color:#fff;border-radius:.4rem;max-width:300PX;min-height:6.66667rem;overflow:hidden;padding:20PX 20PX 10PX;position:relative;width:100%}.login-drawer-wrap .login-drawer-user{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding:.66667rem .4rem}.login-drawer-wrap .login-drawer-user .s-avatar-wrap{height:1.86667rem;margin:0 auto;position:relative;width:1.86667rem}.login-drawer-wrap .login-drawer-user .s-avatar-wrap .icon-vip{bottom:0;position:absolute;right:0}.login-drawer-wrap .login-drawer-user .s-avatar{border-radius:50%;height:1.86667rem;width:1.86667rem}.login-drawer-wrap .login-drawer-user .s-nickname{color:#888;font-size:.37333rem;height:.53333rem;line-height:.53333rem;margin:.26667rem auto auto;max-width:5.33333rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.login-drawer-wrap .login-drawer-user .s-duration{color:#888;font-size:.26667rem;height:.53333rem;line-height:.53333rem;margin:auto;max-width:5.33333rem}.login-drawer-wrap .login-drawer-user .s-duration .s-icon-info{background:url(https://static.ws.126.net/163/wap/f2e/hbs/static/media/info.7ae9b5dda0b334947bba.png) 50%/100% 100% no-repeat;display:inline-block;height:.37333rem;margin:0 0 .06667rem .02667rem;vertical-align:bottom;width:.37333rem}.login-drawer-wrap .login-drawer-user .s-duration .icon-arrow{font-size:.18667rem}.login-drawer-wrap .login-drawer-user .s-duration .s-cancelAuto{text-decoration:underline}.login-drawer-wrap .login-drawer-user .s-duration a{color:#888}.login-drawer-wrap .login-drawer-user .s-link{-webkit-box-pack:justify;-ms-flex-pack:justify;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid #eee;color:#666;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.4rem;height:1.2rem;justify-content:space-between}.login-drawer-wrap .login-drawer-user .s-holder{height:.26667rem}.login-drawer-wrap .login-drawer-user .s-text{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;margin:0 0 0 .53333rem}.login-drawer-wrap .login-drawer-user .icon-email{color:#f33}.login-drawer-wrap .login-drawer-user .icon-talking{color:#f90}.login-drawer-wrap .login-drawer-user .icon-switch{color:#36f}.login-drawer-wrap .login-drawer-user .icon-read{color:#5fa1b3}.toast{-webkit-box-pack:center;-ms-flex-pack:center;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;justify-content:center;left:0;margin:auto;pointer-events:none;position:fixed;right:0;z-index:9999}.toast .toast-content{background-color:rgba(0,0,0,.7);border-radius:.13333rem;color:#fff;font-size:.37333rem;margin-bottom:3.2rem;max-width:75%;min-width:0;opacity:0;padding:.06667rem .2rem;-webkit-transition:opacity .1s linear;transition:opacity .1s linear}.toast .toast-content.toast-content-show{opacity:1} ================================================ FILE: WX/WX-Code/WX-Plugin/Wgllss-Dynamic-Plugin-Sample/wgllss-sample-assets-source-apk/src/main/assets/js/jquery.js ================================================ /*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license //@ sourceMappingURL=jquery.min.map */ (function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
t
",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t }({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
","
"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("