├── .github └── workflows │ └── objective-c-xcode.yml ├── .gitignore ├── H5 └── JDBridge │ ├── Example │ ├── .gitignore │ ├── package.json │ ├── src │ │ ├── index.js │ │ └── jdbridge_demo.html │ └── webpack.config.js │ ├── JDBridge.js │ ├── README.md │ ├── package-lock.json │ └── package.json ├── JDHybrid.podspec ├── LICENSE ├── NOTICE THIRD PARTY ├── README.md ├── android ├── .gitignore ├── JDBridge │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── consumer-rules.pro │ ├── gradle.properties │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── jd │ │ └── jdbridge │ │ ├── JDBridge.kt │ │ ├── JDBridgeConstant.kt │ │ ├── JDBridgeInstaller.kt │ │ ├── JDBridgeManager.kt │ │ ├── Request.kt │ │ ├── Response.kt │ │ ├── WebUtils.kt │ │ └── base │ │ ├── Destroyable.kt │ │ ├── IBridgeCallback.kt │ │ ├── IBridgePlugin.kt │ │ ├── IBridgeProgressCallback.kt │ │ ├── IBridgeWebView.kt │ │ └── IProxy.kt ├── JDCache │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── consumer-rules.pro │ ├── gradle.properties │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── jd │ │ └── jdcache │ │ ├── JDCache.kt │ │ ├── JDCacheConstant.kt │ │ ├── JDCacheLoader.kt │ │ ├── JDCacheLogger.kt │ │ ├── JDCacheParamsProvider.kt │ │ ├── JDCacheSetting.kt │ │ ├── JDCacheWebView.kt │ │ ├── entity │ │ ├── JDCacheDataSource.kt │ │ ├── JDCacheFileDetail.kt │ │ ├── JDCacheLocalResp.kt │ │ └── JDCacheModule.kt │ │ ├── match │ │ ├── PreReadInputStream.kt │ │ ├── ResourceMatcherManager.kt │ │ ├── base │ │ │ └── JDCacheResourceMatcher.kt │ │ └── impl │ │ │ ├── MapResourceMatcher.kt │ │ │ └── PreloadHtmlMatcher.kt │ │ ├── service │ │ ├── DelegateManager.kt │ │ ├── JDCacheMaster.kt │ │ ├── base │ │ │ ├── AbstractDelegate.kt │ │ │ ├── JDCacheFileRepoDelegate.kt │ │ │ └── JDCacheNetDelegate.kt │ │ └── impl │ │ │ ├── FileRepo.kt │ │ │ └── net │ │ │ ├── BaseRequest.kt │ │ │ ├── CallbackInputStream.kt │ │ │ ├── FileRequest.kt │ │ │ ├── HttpRequest.kt │ │ │ ├── NetConnection.kt │ │ │ └── SSLUtils.kt │ │ └── util │ │ ├── CancellableJob.kt │ │ ├── CollectionHelper.kt │ │ ├── CoroutineHelper.kt │ │ ├── FileHelper.kt │ │ ├── ICancellable.kt │ │ ├── IUsefulCheck.kt │ │ ├── JDCacheLog.kt │ │ └── UrlHelper.kt ├── JDWebView │ ├── .gitignore │ ├── README.md │ ├── build.gradle │ ├── consumer-rules.pro │ ├── gradle.properties │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── jd │ │ └── hybrid │ │ └── JDWebView.kt ├── build.gradle ├── example │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ ├── bundle.js │ │ ├── jdbridge_demo.html │ │ └── offline │ │ │ ├── 3jmVvVWpsmP2m1Uab14H8crExDVw │ │ │ ├── b9SI42oS.js │ │ │ ├── hHCmZmSi.js │ │ │ └── resource.json │ │ │ └── m.jd.com │ │ │ ├── 0bH8Cy_E.png │ │ │ ├── 16dlwLEK.jpg │ │ │ ├── 1TcubCmk.png │ │ │ ├── 35j30APx.jpg │ │ │ ├── 3mWEtT0b.js │ │ │ ├── 6f50yYVd.jpg │ │ │ ├── CB50UHti.js │ │ │ ├── CRQluKky.png │ │ │ ├── Dz37ugM_.jpg │ │ │ ├── GSCmQFjj.jpg │ │ │ ├── Gn_eGPZO.ttf │ │ │ ├── Libpn-Ov.jpg │ │ │ ├── LkQ63uZp.js │ │ │ ├── Lr3gFskU.jpg │ │ │ ├── MDzG2XtV.js │ │ │ ├── M_AMl2pj.jpg │ │ │ ├── ORNAUzsj.js │ │ │ ├── OZ9ZSO5c.js │ │ │ ├── PkRd2G0Z.png │ │ │ ├── Q_T4SMwf.css │ │ │ ├── SWYlvsuZ.jpg │ │ │ ├── TnTW3zZp.jpg │ │ │ ├── UaDZq_Qh.jpg │ │ │ ├── VcXzkmlN.css │ │ │ ├── WQIfSFu9.html │ │ │ ├── Yjd75DCK.png │ │ │ ├── aJhypSsa.css │ │ │ ├── dB4FUumh.jpg │ │ │ ├── dlq9hIMc.jpg │ │ │ ├── ffFsGIMV.jpg │ │ │ ├── gTcj0J6H.jpg │ │ │ ├── hdGhsmA-.jpg │ │ │ ├── ia-flqdP.jpg │ │ │ ├── ilpTo4ml.css │ │ │ ├── inT1ic0d.jpg │ │ │ ├── o9aeWBqU.png │ │ │ ├── pPYd-eEI.js │ │ │ ├── resource.json │ │ │ ├── tU6yITBB.jpg │ │ │ ├── uybpB_BU.jpg │ │ │ └── yn-BEciX.jpg │ │ ├── java │ │ └── com │ │ │ └── jd │ │ │ └── hybrid │ │ │ └── example │ │ │ ├── BaseFragment.kt │ │ │ ├── CoroutineHelper.kt │ │ │ ├── GlobalJdBridgePlugin.kt │ │ │ ├── JDBridgeFragment.kt │ │ │ ├── JDCacheFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MyApplication.kt │ │ │ ├── MyHybridParamsProvider.kt │ │ │ ├── MyMatcher.kt │ │ │ ├── MyWebView.kt │ │ │ ├── PerfDialogFragment.kt │ │ │ ├── PerformanceJsBridge.kt │ │ │ ├── Setting.kt │ │ │ ├── SettingActivity.kt │ │ │ ├── SysWebFragment.kt │ │ │ ├── Utils.kt │ │ │ ├── WebActivity.kt │ │ │ └── XConstant.kt │ │ └── res │ │ ├── drawable-hdpi │ │ └── ic_settings.png │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_setting.xml │ │ ├── activity_web.xml │ │ ├── dialog_performance.xml │ │ ├── fragment_jdbridge.xml │ │ ├── fragment_jdcache.xml │ │ ├── fragment_sys_webview.xml │ │ └── fragment_xcache.xml │ │ ├── menu │ │ └── main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── themes.xml ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── doc ├── JDBridge_Timeline.png ├── JDCache_Timeline.jpg ├── ios_resource_match.png ├── ios_resource_match_html.png ├── ios_resource_match_net.png ├── jdcache_process.md └── progress.md ├── iOS ├── Example │ ├── JDHybrid.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── JDHybrid-Example.xcscheme │ ├── JDHybrid.xcworkspace │ │ └── contents.xcworkspacedata │ ├── JDHybrid │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── H5-Example │ │ │ ├── bundle.js │ │ │ ├── dispatchEvent.html │ │ │ └── jdbridge_demo.html │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── JDCacheViewController.h │ │ ├── JDCacheViewController.m │ │ ├── JDCacheWebViewController.h │ │ ├── JDCacheWebViewController.m │ │ ├── JDHybrid-Info.plist │ │ ├── JDHybrid-Prefix.pch │ │ ├── JDMapResourceMatcher.h │ │ ├── JDMapResourceMatcher.m │ │ ├── JDWebViewController.h │ │ ├── JDWebViewController.m │ │ ├── JDXSLViewController.h │ │ ├── JDXSLViewController.m │ │ ├── MyDefaultPlugin.h │ │ ├── MyDefaultPlugin.m │ │ ├── MyNativePlugin.h │ │ ├── MyNativePlugin.m │ │ ├── MySequenceNativePlugin.h │ │ ├── MySequenceNativePlugin.m │ │ ├── XHAppDelegate.h │ │ ├── XHAppDelegate.m │ │ ├── XHCache.h │ │ ├── XHCache.m │ │ ├── XHDefine.h │ │ ├── XHViewController.h │ │ ├── XHViewController.m │ │ ├── XImageElement.h │ │ ├── XImageElement.m │ │ ├── en.lproj │ │ │ └── InfoPlist.strings │ │ ├── main.m │ │ ├── resource │ │ │ ├── 0bH8Cy_E.png │ │ │ ├── 16dlwLEK.jpg │ │ │ ├── 1TcubCmk.png │ │ │ ├── 35j30APx.jpg │ │ │ ├── 3mWEtT0b.js │ │ │ ├── 6f50yYVd.jpg │ │ │ ├── CB50UHti.js │ │ │ ├── CRQluKky.png │ │ │ ├── Dz37ugM_.jpg │ │ │ ├── GSCmQFjj.jpg │ │ │ ├── Gn_eGPZO.ttf │ │ │ ├── Libpn-Ov.jpg │ │ │ ├── LkQ63uZp.js │ │ │ ├── Lr3gFskU.jpg │ │ │ ├── MDzG2XtV.js │ │ │ ├── M_AMl2pj.jpg │ │ │ ├── ORNAUzsj.js │ │ │ ├── OZ9ZSO5c.js │ │ │ ├── PkRd2G0Z.png │ │ │ ├── Q_T4SMwf.css │ │ │ ├── SWYlvsuZ.jpg │ │ │ ├── TnTW3zZp.jpg │ │ │ ├── UaDZq_Qh.jpg │ │ │ ├── VcXzkmlN.css │ │ │ ├── WQIfSFu9.html │ │ │ ├── Yjd75DCK.png │ │ │ ├── aJhypSsa.css │ │ │ ├── dB4FUumh.jpg │ │ │ ├── dlq9hIMc.jpg │ │ │ ├── ffFsGIMV.jpg │ │ │ ├── gTcj0J6H.jpg │ │ │ ├── hdGhsmA-.jpg │ │ │ ├── ia-flqdP.jpg │ │ │ ├── ilpTo4ml.css │ │ │ ├── inT1ic0d.jpg │ │ │ ├── o9aeWBqU.png │ │ │ ├── pPYd-eEI.js │ │ │ ├── resource.json │ │ │ ├── tU6yITBB.jpg │ │ │ ├── uybpB_BU.jpg │ │ │ └── yn-BEciX.jpg │ │ └── xsl-index.html │ ├── JDHybrid_Example.entitlements │ ├── Podfile │ ├── Podfile.lock │ └── Tests │ │ ├── Tests-Info.plist │ │ ├── Tests-Prefix.pch │ │ ├── Tests.m │ │ └── en.lproj │ │ └── InfoPlist.strings └── JDHybrid │ ├── JDBridge │ ├── Classes │ │ ├── JDBridgeBasePlugin.h │ │ ├── JDBridgeBasePlugin.m │ │ ├── JDBridgeBasePluginPrivate.h │ │ ├── JDBridgeManager.h │ │ ├── JDBridgeManager.m │ │ ├── JDBridgeManagerPrivate.h │ │ ├── JDBridgePluginUtils.h │ │ ├── JDBridgePluginUtils.m │ │ ├── _jdbridge.h │ │ └── _jdbridge.m │ ├── JDBridge.h │ └── README.md │ ├── JDCache │ ├── Assets │ │ ├── .gitkeep │ │ ├── cookie.js │ │ └── hook.js │ ├── Classes │ │ ├── .gitkeep │ │ ├── Configure │ │ │ ├── JDCacheLoader.h │ │ │ ├── JDCacheLoader.m │ │ │ ├── WKWebViewConfiguration+Loader.h │ │ │ └── WKWebViewConfiguration+Loader.m │ │ ├── JDCache.h │ │ ├── JDCache.m │ │ ├── JDCacheProtocol.h │ │ ├── JSBridge │ │ │ ├── JDCacheJSBridge.h │ │ │ └── JDCacheJSBridge.m │ │ ├── Network │ │ │ ├── JDCachedURLResponse.h │ │ │ ├── JDCachedURLResponse.m │ │ │ ├── JDNetworkManager.h │ │ │ ├── JDNetworkManager.m │ │ │ ├── JDNetworkOperationQueue.h │ │ │ ├── JDNetworkOperationQueue.m │ │ │ ├── JDNetworkSession.h │ │ │ ├── JDNetworkSession.m │ │ │ ├── JDURLCache.h │ │ │ └── JDURLCache.m │ │ ├── Preload │ │ │ ├── JDCachePreload.h │ │ │ └── JDCachePreload.m │ │ ├── ResourceMatcher │ │ │ ├── JDNetworkResourceMatcher.h │ │ │ ├── JDNetworkResourceMatcher.m │ │ │ ├── JDPreloadHtmlMatcher.h │ │ │ ├── JDPreloadHtmlMatcher.m │ │ │ ├── JDResourceMatcherIterator.h │ │ │ ├── JDResourceMatcherIterator.m │ │ │ ├── JDResourceMatcherManager.h │ │ │ └── JDResourceMatcherManager.m │ │ └── Utils │ │ │ ├── JDSafeArray.h │ │ │ ├── JDSafeArray.m │ │ │ ├── JDSafeDictionary.h │ │ │ ├── JDSafeDictionary.m │ │ │ ├── JDUtils.h │ │ │ ├── JDUtils.m │ │ │ ├── JDWeakProxy.h │ │ │ └── JDWeakProxy.m │ └── README.md │ ├── JDHybrid.h │ ├── JDWebView │ ├── Assets │ │ └── .gitkeep │ ├── Classes │ │ ├── .gitkeep │ │ ├── JDWebViewContainer.h │ │ └── JDWebViewContainer.m │ ├── JDWebView.h │ └── README.md │ └── JDXSL │ ├── JDHybridXSLContainerView.h │ ├── JDHybridXSLContainerView.m │ ├── JDHybridXSLRegister.h │ ├── JDHybridXSLRegister.m │ ├── JDXSLBaseElement.h │ ├── JDXSLBaseElement.m │ ├── JDXSLManager.h │ ├── JDXSLManager.m │ ├── XWidgetPlugin.h │ ├── XWidgetPlugin.m │ ├── hybrid_hook_xsl_js.h │ └── hybrid_hook_xsl_js.m └── nodejs ├── .vscode └── launch.json ├── README.md ├── app.js ├── package.json ├── public ├── iconfont │ ├── iconfont.css │ ├── iconfont.js │ ├── iconfont.json │ ├── iconfont.ttf │ ├── iconfont.woff │ └── iconfont.woff2 ├── index.html ├── static │ └── img.jpg ├── upload │ └── index.html └── utils.js └── src ├── urlParse.js └── zipCreate.js /.github/workflows/objective-c-xcode.yml: -------------------------------------------------------------------------------- 1 | name: Xcode - Build and Analyze 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | name: Build and analyse default scheme using xcodebuild command 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | - name: Set Default Scheme 18 | run: | 19 | scheme_list=$(cd ./iOS/Example | xcodebuild -list -json | tr -d "\n") 20 | default=$(echo $scheme_list | ruby -e "require 'json'; puts JSON.parse(STDIN.gets)['project']['targets'][0]") 21 | echo $default | cat >default 22 | echo Using default scheme: $default 23 | - name: Build 24 | env: 25 | scheme: ${{ 'default' }} 26 | run: | 27 | if [ $scheme = default ]; then scheme=$(cat default); fi 28 | if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi 29 | file_to_build=`echo $file_to_build | awk '{$1=$1;print}'` 30 | xcodebuild clean build analyze -scheme "$scheme" -"$filetype_parameter" "$file_to_build" | xcpretty && exit ${PIPESTATUS[0]} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | */.DS_Store 4 | 5 | # Xcode 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata/ 16 | *.xccheckout 17 | profile 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | Pods/ 23 | # Bundler 24 | .bundle 25 | *.moved-aside 26 | *.xcuserstate 27 | *.xcscmblueprint 28 | 29 | ## Various settings 30 | *.pbxuser 31 | !default.pbxuser 32 | *.mode1v3 33 | !default.mode1v3 34 | *.mode2v3 35 | !default.mode2v3 36 | *.perspectivev3 37 | !default.perspectivev3 38 | xcuserdata 39 | xcshareddata 40 | 41 | ## Other 42 | *.xccheckout 43 | *.moved-aside 44 | *.xcuserstate 45 | *.xcscmblueprint 46 | #*.xcworkspacedata 47 | 48 | ## Obj-C/Swift specific 49 | *.hmap 50 | *.ipa 51 | 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # We recommend against adding the Pods directory to your .gitignore. However 58 | # you should judge for yourself, the pros and cons are mentioned at: 59 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 60 | # 61 | # Note: if you ignore the Pods directory, make sure to uncomment 62 | # `pod install` in .travis.yml 63 | # 64 | # Pods/ 65 | node_modules/ 66 | uploads/ 67 | ziparc/ 68 | package-lock.json 69 | -------------------------------------------------------------------------------- /H5/JDBridge/Example/.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | build/ 5 | dist/ 6 | node_modules/ 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /H5/JDBridge/Example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "npmtest", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack && cp -r dist/. ../../../android/Example/src/main/assets && cp -r dist/. ../../../iOS/Example/JDHybrid/H5-Example", 8 | "clean": "rm -rf dist" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "html-webpack-plugin": "^5.5.0", 15 | "webpack": "^5.74.0", 16 | "webpack-cli": "^4.10.0" 17 | }, 18 | "dependencies": { 19 | "jdhybrid_jdbridge": "^1.0.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /H5/JDBridge/Example/src/index.js: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2022 JD.com, Inc. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | // 24 | var JDBridge = require("jdhybrid_jdbridge") -------------------------------------------------------------------------------- /H5/JDBridge/Example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | const { resolve } = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/index.js', 6 | output: { 7 | path: resolve(__dirname, './dist'), 8 | filename: 'bundle.js', 9 | }, 10 | plugins: [ 11 | new HtmlWebpackPlugin({ 12 | template: './src/jdbridge_demo.html', 13 | filename: 'jdbridge_demo.html' 14 | }) 15 | ], 16 | mode: 'development' 17 | }; -------------------------------------------------------------------------------- /H5/JDBridge/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jdhybrid_jdbridge", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "jdhybrid_jdbridge", 9 | "version": "1.0.0", 10 | "license": "MIT" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /H5/JDBridge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jdhybrid_jdbridge", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./JDBridge.js", 6 | "author": "jdhybrid", 7 | "license": "MIT" 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 JD.com, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

简介

3 | JDHybrid是一个移动端高性能Hybrid容器框架,致力于提升h5加载与渲染性能、WebView容器标准化,项目经过了亿级PV的业务验证, 项目主要包括: 4 | 5 | * jsbridge --- JDBridge 6 | * 集成各种开源能力的WebView容器 --- JDWebView 7 | * 离线包加载框架 --- JDCache 8 | * iOS同层渲染 --- JDWidget(正在路上...) 9 | 10 | 11 |

快速入门指南

12 |

使用JSBridge

13 | JSBridge(JDBridge) 包含jssdk部分与客户端部分,使用时js先引入JSSDK(见下文), 并添加js插件供native调用,或通过jssdk api调用native插件,使用方式参考: 14 | 15 | * [H5 JSBridge](H5/JDBridge/README.md) 16 | * [iOS JSBridge](iOS/JDHybrid/JDBridge/README.md) 17 | * [Android JSBridge](android/JDBridge/README.md) 18 | 19 |

使用WebView容器

20 | JDHybrid 提供了支持JDBridge的容器,未来还会支持离线加载能力,可直接使用 21 | 22 | * [iOS WebView容器](iOS/JDHybrid/JDWebView/README.md) 23 | * [Android WebView容器](android/JDWebView/README.md) 24 | 25 |

使用JDCache

26 | 27 | * [iOS JDCache](iOS/JDHybrid/JDCache/README.md) 28 | * [Android JDCache](android/JDCache/README.md) 29 | * [离线包制作](nodejs/README.md) 30 | 31 |

更多使用方式

32 | 33 | * [h5 Demo](H5/JDBridge/Example) 进入[H5/JDBridge/Example](H5/JDBridge/Example)下执行 `npm install && npm run build` , 打开 `dist` 文件夹内的html即可, 客户端试用下面Demo前也请先安装h5 demo,我们会自动copy产物到Example内 34 | * [iOS Demo](iOS/Example) 进入[iOS/Example](/iOS/Example)文件夹,执行 `pod install` 35 | * [Android Demo ](android/example)进入[android](/android)文件夹,执行`./gradlew installDebug` 36 | 37 |

Contributing

38 | 我们欢迎您能为JDHybrid做出贡献帮助它变得更好!我们鼓励并重视所有类型的贡献。如果你有任何问题,请随时在我们的讨论区开启一个新的讨论主题。 39 | 如果您有webview方面的诉求,也可以提出需求。 40 |

License

41 | JDHybrid(包括子项目) 基于MIT协议开源,具体查看 LICENSE 文件了解更多信息. 42 | 43 | 44 |

Contact

45 | 46 | 邮箱: hybrid@jd.com 47 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | .gradle 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | .settings 18 | -------------------------------------------------------------------------------- /android/JDBridge/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android/JDBridge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | id 'maven-publish' 5 | } 6 | 7 | android { 8 | compileSdkVersion 31 9 | 10 | defaultConfig { 11 | minSdkVersion 16 12 | targetSdkVersion 31 13 | 14 | consumerProguardFiles "consumer-rules.pro" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | dependencies { 30 | 31 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 32 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$ktCoroutineVer" 33 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$ktCoroutineVer" 34 | } 35 | 36 | Properties properties = new Properties() 37 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 38 | def name = properties.getProperty('username') 39 | def pw = properties.getProperty('password') 40 | def releasesRepoUrl = properties.getProperty('releaseUrl') 41 | def snapshotsRepoUrl = properties.getProperty('snapshotsUrl') 42 | 43 | task androidSourcesJar(type: Jar) { 44 | archiveClassifier.set('sources') 45 | from android.sourceSets.main.java.srcDirs 46 | } 47 | 48 | publishing { 49 | repositories { 50 | maven { 51 | allowInsecureProtocol true 52 | credentials{ 53 | username name 54 | password pw 55 | } 56 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl: releasesRepoUrl 57 | } 58 | } 59 | publications { 60 | release(MavenPublication) { 61 | groupId = 'com.jd.libs' 62 | artifactId = "$artifactId" 63 | version = "$version" 64 | 65 | artifact(androidSourcesJar)//打包源码到aar,使宿主可调试 66 | 67 | afterEvaluate { 68 | from components.release 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /android/JDBridge/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/JDBridge/consumer-rules.pro -------------------------------------------------------------------------------- /android/JDBridge/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | #org.gradle.jvmargs=-Xmx2048m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | artifactId=jdbridge 18 | version=1.0.1 19 | 20 | -------------------------------------------------------------------------------- /android/JDBridge/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles SETTING_DATA in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android/JDBridge/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/JDBridgeConstant.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge 26 | 27 | object JDBridgeConstant { 28 | 29 | const val MODULE_TAG = "JDBridge" 30 | 31 | const val JS_PREFIX = "javascript:" 32 | 33 | const val JS_TRY_WARP = "javascript:try{%s}catch(e){console&&console.error(e)}" 34 | 35 | const val JS_CALL_WEB = "window.JDBridge._handleRequestFromNative(%s)" 36 | 37 | const val JS_RESPOND_TO_WEB = "window.JDBridge._handleResponseFromNative(%s)" 38 | 39 | const val JS_DISPATCH_EVENT = 40 | ";(function(){" + 41 | "var event = new CustomEvent('%s', {'detail': %s}); " + 42 | "window.dispatchEvent(event);" + 43 | "})();" 44 | 45 | const val JS_ALERT_DEBUG_MSG = "alert('JDBridge Debug Msg: %s')" 46 | 47 | const val JS_SET_DEBUG = "window.JDBridge.setDebug(%b)" 48 | 49 | const val STATUS_SUCCESS = "0" 50 | const val STATUS_ERROR = "-1" 51 | const val STATUS_EXCEPTION = "1" 52 | const val STATUS_NOT_FOUND = "-2" 53 | 54 | const val MSG_PLUGIN_NOT_FOUND = "Target plugin not found." 55 | const val MSG_ACTION_NOT_FOUND = "Target action not found." 56 | const val MSG_EXCEPTION = "Execute plugin throws." 57 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/JDBridgeInstaller.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge 26 | 27 | import com.jd.jdbridge.base.IBridgeWebView 28 | import com.jd.jdbridge.base.IProxy 29 | import com.jd.jdbridge.base.registerBridge 30 | 31 | class JDBridgeInstaller { 32 | 33 | val bridgeMap: MutableMap = HashMap(1) 34 | 35 | private lateinit var jsBridge: JDBridge 36 | 37 | fun install(actualView: IBridgeWebView){ 38 | jsBridge = JDBridge(actualView) 39 | actualView.registerBridge(jsBridge) 40 | } 41 | 42 | fun loadUrl(url: String) { 43 | if (url.startsWith("http") || url.startsWith("file")) { 44 | jsBridge.startQueueRequest() 45 | } 46 | } 47 | 48 | fun reload() { 49 | jsBridge.startQueueRequest() 50 | } 51 | 52 | fun onStart() { 53 | jsBridge.onStart() 54 | } 55 | 56 | fun onResume() { 57 | jsBridge.onResume() 58 | } 59 | 60 | fun onPause() { 61 | jsBridge.onPause() 62 | } 63 | 64 | fun onStop() { 65 | jsBridge.onStop() 66 | } 67 | 68 | fun destroy() { 69 | jsBridge.destroy() 70 | } 71 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/Request.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge 26 | 27 | import android.util.Log 28 | import com.jd.jdbridge.JDBridgeConstant.MODULE_TAG 29 | import com.jd.jdbridge.base.IBridgeCallback 30 | import org.json.JSONException 31 | import org.json.JSONObject 32 | 33 | data class Request( 34 | val plugin: String? = null, 35 | val params: Any? = null, 36 | val callbackId: String? = null 37 | ) { 38 | var action: String? = null // only needed when js calls native 39 | var callback: IBridgeCallback? = null 40 | 41 | override fun toString(): String { 42 | val jsonObj = JSONObject() 43 | try { 44 | jsonObj.put("plugin", plugin) 45 | jsonObj.put("action", action) 46 | jsonObj.put("params", params) 47 | jsonObj.put("callbackId", callbackId) 48 | } catch (e: JSONException) { 49 | if (JDBridgeManager.webDebug) { 50 | Log.e("${MODULE_TAG}-Request", e.message, e) 51 | } 52 | } 53 | return JSONObject.quote(jsonObj.toString()) 54 | } 55 | } 56 | 57 | internal fun JSONObject.toRequest(): Request { 58 | val request = Request( 59 | optString("plugin", "").ifEmpty { null }, 60 | opt("params"), 61 | optString("callbackId", "").ifEmpty { null }) 62 | request.action = optString("action", "").ifEmpty { null } 63 | return request 64 | } 65 | -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/Response.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge 26 | 27 | import android.util.Log 28 | import org.json.JSONException 29 | import org.json.JSONObject 30 | 31 | data class Response( 32 | val status: String, 33 | val callbackId: String? = null, 34 | val data: Any? = null, 35 | val msg: String? = null, 36 | val complete: Boolean = true 37 | ) { 38 | 39 | override fun toString(): String { 40 | val jsonObj = JSONObject() 41 | try { 42 | jsonObj.put("status", status) 43 | jsonObj.put("callbackId", callbackId) 44 | jsonObj.put("data", data) 45 | jsonObj.put("msg", msg) 46 | jsonObj.put("complete", complete) 47 | } catch (e: JSONException) { 48 | if (JDBridgeManager.webDebug) { 49 | Log.e("${JDBridgeConstant.MODULE_TAG}-Response", e.message, e) 50 | } 51 | } 52 | return WebUtils.string2JsStr(jsonObj.toString()) 53 | } 54 | } 55 | 56 | internal fun JSONObject.toResponse(): Response { 57 | return Response( 58 | optString("status", "0"), 59 | optString("callbackId", "").ifEmpty { null }, 60 | opt("data"), 61 | optString("msg", "").ifEmpty { null }, 62 | optBoolean("complete", true)) 63 | } 64 | -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/base/Destroyable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge.base 26 | 27 | interface Destroyable { 28 | fun destroy() 29 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/base/IBridgeCallback.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge.base 26 | 27 | interface IBridgeCallback { 28 | fun onSuccess(result: Any?) 29 | 30 | fun onError(errMsg: String?) { 31 | //default implementation 32 | } 33 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/base/IBridgePlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge.base 26 | 27 | interface IBridgePlugin { 28 | fun execute( 29 | webView: IBridgeWebView?, 30 | method: String?, 31 | params: String?, 32 | callback: IBridgeCallback? 33 | ): Boolean 34 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/base/IBridgeProgressCallback.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge.base 26 | 27 | interface IBridgeProgressCallback : IBridgeCallback { 28 | fun onProgress(data: Any?) 29 | } -------------------------------------------------------------------------------- /android/JDBridge/src/main/java/com/jd/jdbridge/base/IProxy.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.jdbridge.base 26 | 27 | interface IProxy { 28 | val name: String 29 | } -------------------------------------------------------------------------------- /android/JDCache/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android/JDCache/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | id 'maven-publish' 5 | } 6 | 7 | android { 8 | compileSdkVersion 31 9 | 10 | defaultConfig { 11 | minSdkVersion 21 12 | targetSdkVersion 31 13 | 14 | consumerProguardFiles "consumer-rules.pro" 15 | } 16 | 17 | buildTypes { 18 | debug { 19 | minifyEnabled Boolean.parseBoolean(rootProject.minifyEnabled) 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | 23 | release { 24 | minifyEnabled Boolean.parseBoolean(rootProject.minifyEnabled) 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | compileOptions { 29 | sourceCompatibility JavaVersion.VERSION_1_8 30 | targetCompatibility JavaVersion.VERSION_1_8 31 | } 32 | } 33 | 34 | dependencies { 35 | 36 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 37 | // implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" 38 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$ktCoroutineVer" 39 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion" 40 | 41 | } 42 | 43 | Properties properties = new Properties() 44 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 45 | def name = properties.getProperty('username') 46 | def pw = properties.getProperty('password') 47 | def releasesRepoUrl = properties.getProperty('releaseUrl') 48 | def snapshotsRepoUrl = properties.getProperty('snapshotsUrl') 49 | 50 | task androidSourcesJar(type: Jar) { 51 | archiveClassifier.set('sources') 52 | from android.sourceSets.main.java.srcDirs 53 | } 54 | 55 | publishing { 56 | repositories { 57 | maven { 58 | allowInsecureProtocol true 59 | credentials{ 60 | username name 61 | password pw 62 | } 63 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl: releasesRepoUrl 64 | } 65 | } 66 | publications { 67 | release(MavenPublication) { 68 | groupId = "${project.groupId}" 69 | artifactId = "${project.artifactId}" 70 | version = "$version" 71 | 72 | artifact(androidSourcesJar)//打包源码到aar,使宿主可调试 73 | 74 | afterEvaluate { 75 | from components.release 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /android/JDCache/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/JDCache/consumer-rules.pro -------------------------------------------------------------------------------- /android/JDCache/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | #org.gradle.jvmargs=-Xmx2048m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | groupId=com.jingdong.wireless.jdsdk 18 | artifactId=jdhybrid-cache 19 | version=1.0.0-beta-3 20 | 21 | -------------------------------------------------------------------------------- /android/JDCache/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles SETTING_DATA in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -flattenpackagehierarchy 'com.jd.jdcache' 24 | 25 | # Keep `Companion` object fields of serializable classes. 26 | # This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. 27 | -if @kotlinx.serialization.Serializable class ** 28 | -keepclassmembers class <1> { 29 | static <1>$Companion Companion; 30 | } 31 | 32 | # Keep `serializer()` on companion objects (both default and named) of serializable classes. 33 | -if @kotlinx.serialization.Serializable class ** { 34 | static **$* *; 35 | } 36 | -keepclassmembers class <2>$<3> { 37 | kotlinx.serialization.KSerializer serializer(...); 38 | } 39 | 40 | # Keep `INSTANCE.serializer()` of serializable objects. 41 | -if @kotlinx.serialization.Serializable class ** { 42 | public static ** INSTANCE; 43 | } 44 | -keepclassmembers class <1> { 45 | public static <1> INSTANCE; 46 | kotlinx.serialization.KSerializer serializer(...); 47 | } 48 | 49 | # @Serializable and @Polymorphic are used at runtime for polymorphic serialization. 50 | -keepattributes RuntimeVisibleAnnotations,AnnotationDefault 51 | 52 | # Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`. 53 | # If you have any, uncomment and replace classes with those containing named companion objects. 54 | #-keepattributes InnerClasses # Needed for `getDeclaredClasses`. 55 | #-if @kotlinx.serialization.Serializable class 56 | #com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions. 57 | #com.example.myapplication.HasNamedCompanion2 58 | #{ 59 | # static **$* *; 60 | #} 61 | #-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept. 62 | # static <1>$$serializer INSTANCE; 63 | #} -------------------------------------------------------------------------------- /android/JDCache/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/JDCacheConstant.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache 2 | 3 | import kotlinx.coroutines.CoroutineScope 4 | import kotlinx.coroutines.Dispatchers 5 | import kotlinx.coroutines.SupervisorJob 6 | 7 | internal object JDCacheConstant { 8 | internal val applicationScope by lazy { CoroutineScope(SupervisorJob()) } 9 | 10 | internal val ioDispatcher by lazy { Dispatchers.IO } 11 | internal val mainDispatcher by lazy { Dispatchers.Main.immediate } 12 | 13 | const val NET_READ_BUFFER_SIZE = 1024 * 10 14 | const val LOCAL_READ_BUFFER_SIZE = 1024 * 2 15 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/JDCacheLogger.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache 2 | 3 | import androidx.annotation.Keep 4 | 5 | @Keep 6 | interface JDCacheLogger { 7 | fun d(msg: String?) 8 | fun d(tag: String?, msg: String?) 9 | fun d(tag: String?, t: Throwable?) 10 | fun d(tag: String?, msg: String?, t: Throwable?) 11 | fun w(msg: String?) 12 | fun w(tag: String?, msg: String?) 13 | fun w(tag: String?, t: Throwable?) 14 | fun w(tag: String?, msg: String?, t: Throwable?) 15 | fun e(msg: String?) 16 | fun e(tag: String?, msg: String?) 17 | fun e(tag: String?, t: Throwable?) 18 | fun e(tag: String?, msg: String?, t: Throwable?) 19 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/JDCacheSetting.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache 2 | 3 | import android.content.Context 4 | import com.jd.jdcache.util.JDCacheLog.e 5 | import com.jd.jdcache.util.log 6 | 7 | internal object JDCacheSetting { 8 | var appContext: Context? = null 9 | var debug: Boolean = false 10 | var enable: Boolean = true 11 | 12 | // private var globalParamsClassChanged = AtomicBoolean(true) 13 | 14 | private var paramsProviderClass: Class = JDCacheParamsProvider::class.java 15 | 16 | fun setGlobalParamsClass(clazz: Class) { 17 | paramsProvider = null 18 | // globalParamsClassChanged.set(true) 19 | paramsProviderClass = clazz 20 | } 21 | 22 | private var paramsProvider: JDCacheParamsProvider? = null 23 | 24 | fun getParamsProvider(): JDCacheParamsProvider? { 25 | if (paramsProvider == null) { 26 | synchronized(this) { 27 | if (paramsProvider == null) { 28 | try { 29 | paramsProvider = paramsProviderClass.newInstance() 30 | } catch (e: Throwable) { 31 | //这里不套log{ },因为会循环调用canLog方法 32 | e("JDCacheSetting", "Error in creating global params", e) 33 | } 34 | } 35 | } 36 | } 37 | return paramsProvider 38 | } 39 | 40 | 41 | // var paramsProvider: JDCacheParamsProvider? = null 42 | // private set 43 | // get() { 44 | // field = if (globalParamsClassChanged.compareAndSet(true, false)) { 45 | // try { 46 | // paramsProviderClass.createInstance() 47 | // } catch (e: Exception) { 48 | // log { e("JDCacheSetting", "Error in creating global params", e) } 49 | // null 50 | // } 51 | // } else { 52 | // field 53 | // } 54 | // return field 55 | // } 56 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/JDCacheWebView.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache 2 | 3 | import android.view.View 4 | import android.webkit.ValueCallback 5 | import androidx.annotation.Keep 6 | 7 | @Keep 8 | interface JDCacheWebView { 9 | 10 | val view: View? 11 | 12 | fun addJavascriptInterface(obj: Any, interfaceName: String) 13 | 14 | fun evaluateJavascript(script: String, resultCallback: ValueCallback?) 15 | 16 | fun reload() 17 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/entity/JDCacheFileDetail.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.entity 2 | 3 | import androidx.annotation.Keep 4 | import java.io.File 5 | 6 | @Keep 7 | data class JDCacheFileDetail constructor( 8 | /** 文件路径 */ 9 | var path: String, 10 | /** 11 | * 上次修改时间 12 | */ 13 | var lastModified: Long = 0, 14 | /** 15 | * 文件大小 16 | */ 17 | var totalSpace: Long = 0 18 | ) { 19 | 20 | constructor(file: File) : this(file.absolutePath, file.lastModified(), file.totalSpace) 21 | 22 | fun exists(): Boolean { 23 | val file = File(path) 24 | return file.exists() 25 | } 26 | 27 | fun hasChanged(): Boolean { 28 | val file = File(path) 29 | return !file.exists() || file.lastModified() != lastModified 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/entity/JDCacheModule.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.entity 2 | 3 | import android.text.TextUtils 4 | import androidx.annotation.Keep 5 | import kotlin.random.Random 6 | 7 | @Keep 8 | data class JDCacheModule( 9 | var configId: String = generateRandomId(), 10 | var url: String? = null, 11 | var urlType: Short = URL_TYPE_NORMAL, 12 | var createTime: Long = System.currentTimeMillis() 13 | ) { 14 | 15 | companion object { 16 | const val URL_TYPE_NORMAL: Short = 1 17 | const val URL_TYPE_REGEXP: Short = 2 18 | 19 | private fun generateRandomId(): String { 20 | return "${System.currentTimeMillis()}-${Random.nextInt(100, 1000)}" 21 | } 22 | } 23 | 24 | val isRegexpUrl: Boolean 25 | get() = (URL_TYPE_REGEXP == urlType && !TextUtils.isEmpty(url)) 26 | 27 | override fun equals(other: Any?): Boolean { 28 | if (this === other) { 29 | return true 30 | } 31 | if (other == null || other !is JDCacheModule) { 32 | return false 33 | } 34 | return configId == other.configId 35 | } 36 | 37 | override fun hashCode(): Int { 38 | return configId.hashCode() 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/match/ResourceMatcherManager.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.match 2 | 3 | import com.jd.jdcache.match.base.JDCacheResourceMatcher 4 | import com.jd.jdcache.util.JDCacheLog.e 5 | import com.jd.jdcache.util.log 6 | import java.lang.reflect.Modifier 7 | import java.util.* 8 | 9 | internal object ResourceMatcherManager { 10 | private const val TAG = "ResourceMatcherManager" 11 | 12 | private val defaultMatcherClassList : MutableList> by lazy { 13 | LinkedList>() 14 | } 15 | 16 | fun registerMatcher(matcherClass: Class) { 17 | val modifier = matcherClass.modifiers 18 | if (Modifier.isAbstract(modifier) || Modifier.isInterface(modifier)) { 19 | log { e(TAG, "Error in adding register matcher class. " + 20 | "Cannot register abstract class.") } 21 | return 22 | } 23 | if (matcherClass == JDCacheResourceMatcher::class) { 24 | log { e(TAG, "Error in adding register matcher class. " + 25 | "Cannot add JDCacheResourceMatcher directly, you need to implement this class.") 26 | } 27 | return 28 | } 29 | defaultMatcherClassList.add(matcherClass) 30 | } 31 | 32 | fun unregisterMatcher(matcherClass: Class) { 33 | defaultMatcherClassList.remove(matcherClass) 34 | } 35 | 36 | fun clearMatcher(){ 37 | defaultMatcherClassList.clear() 38 | } 39 | 40 | fun createMatcher(clazz: Class): JDCacheResourceMatcher? { 41 | return try { 42 | clazz.newInstance() 43 | } catch (e: Throwable) { 44 | log { e(TAG, "Error in creating matcher instance for ${clazz.simpleName}", e) } 45 | null 46 | } 47 | } 48 | 49 | fun createDefaultMatcherList(): LinkedList { 50 | val matcherList = LinkedList() 51 | defaultMatcherClassList.forEach { clazz -> 52 | try { 53 | matcherList.add(clazz.newInstance()) 54 | } catch (e: Throwable) { 55 | log { e(TAG, "Error in creating matcher instance for ${clazz.simpleName}", e) } 56 | } 57 | } 58 | return matcherList 59 | } 60 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/match/base/JDCacheResourceMatcher.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.match.base 2 | 3 | import android.webkit.WebResourceRequest 4 | import android.webkit.WebResourceResponse 5 | import androidx.annotation.CallSuper 6 | import androidx.annotation.Keep 7 | import androidx.annotation.WorkerThread 8 | import androidx.lifecycle.Lifecycle 9 | import com.jd.jdcache.JDCacheLoader 10 | import java.io.FileInputStream 11 | import java.io.InputStream 12 | import java.util.concurrent.atomic.AtomicBoolean 13 | 14 | @Keep 15 | abstract class JDCacheResourceMatcher { 16 | 17 | abstract val name: String 18 | 19 | var loader: JDCacheLoader? = null 20 | 21 | protected val destroyed = AtomicBoolean(false) 22 | 23 | open fun onLifecycleStateChanged(event: Lifecycle.Event) { 24 | if (event == Lifecycle.Event.ON_DESTROY) { 25 | destroy() 26 | } 27 | } 28 | 29 | open fun prepare(url: String) { 30 | } 31 | 32 | @WorkerThread 33 | abstract fun match(request: WebResourceRequest): WebResourceResponse? 34 | 35 | fun destroy(){ 36 | if (destroyed.compareAndSet(false, true)) { 37 | onDestroy() 38 | } 39 | } 40 | 41 | @CallSuper 42 | protected open fun onDestroy() { 43 | loader = null 44 | } 45 | 46 | protected open fun createResponse( 47 | mimeType: String, 48 | encoding: String?, 49 | header: MutableMap?, 50 | filePath: String 51 | ): WebResourceResponse { 52 | return createResponse(mimeType, encoding, header, FileInputStream(filePath)) 53 | } 54 | 55 | protected open fun createResponse( 56 | mimeType: String, 57 | encoding: String?, 58 | header: MutableMap?, 59 | inputStream: InputStream 60 | ): WebResourceResponse { 61 | return createResponse(WebResourceResponse(mimeType, encoding, inputStream)) 62 | } 63 | 64 | protected open fun createResponse( 65 | response: WebResourceResponse 66 | ): WebResourceResponse { 67 | response.responseHeaders = response.responseHeaders ?: HashMap(1) 68 | response.responseHeaders["JDCache"] = name 69 | return response 70 | } 71 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/service/JDCacheMaster.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.service 2 | 3 | import com.jd.jdcache.JDCacheLoader 4 | import com.jd.jdcache.util.JDCacheLog.d 5 | import com.jd.jdcache.util.log 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | /** 9 | * hybrid逻辑中枢 10 | */ 11 | internal class JDCacheMaster private constructor() { 12 | 13 | private val loaderMap by lazy { ConcurrentHashMap() } 14 | 15 | //单例 16 | companion object { 17 | private const val TAG = "JDCacheMaster" 18 | @Volatile 19 | private var INSTANCE: JDCacheMaster? = null 20 | 21 | fun getInstance(): JDCacheMaster = 22 | //双重校验锁 23 | INSTANCE ?: synchronized(this) { 24 | INSTANCE ?: JDCacheMaster().also { INSTANCE = it } 25 | } 26 | } 27 | 28 | init { 29 | } 30 | 31 | // fun addModule(config: JDCacheModule?) { 32 | // config?.let { 33 | // ConfigService.getInstance().save(config) 34 | // } 35 | // } 36 | // 37 | // fun removeModule(config: JDCacheModule?) { 38 | // config?.let { 39 | // ConfigService.getInstance().delete(config) 40 | // } 41 | // } 42 | 43 | fun createDefaultLoader(url: String): JDCacheLoader { 44 | val id = System.currentTimeMillis().toString() 45 | val loader = JDCacheLoader(url, id).init() 46 | log { d(TAG, "Create new loader(id:${loader.key}) for ${loader.url}") } 47 | loaderMap[loader.key] = loader 48 | return loader 49 | } 50 | 51 | fun addLoader(loader: JDCacheLoader) { 52 | log { d(TAG, "Add new loader(id:${loader.key}) for ${loader.url}") } 53 | loaderMap[loader.key] = loader 54 | } 55 | 56 | fun getLoader(loaderKey: String): JDCacheLoader? { 57 | return loaderMap[loaderKey] 58 | } 59 | 60 | fun removeLoader(loaderKey: String): JDCacheLoader? { 61 | val removed = loaderMap.remove(loaderKey) 62 | log { 63 | removed?.let { d(TAG, "Remove loader(id:${removed.key})") } 64 | } 65 | return removed 66 | } 67 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/service/base/AbstractDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.service.base 2 | 3 | import androidx.annotation.Keep 4 | 5 | @Keep 6 | abstract class AbstractDelegate { 7 | abstract val name: String 8 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/service/impl/net/CallbackInputStream.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.service.impl.net 2 | 3 | import java.io.InputStream 4 | 5 | internal class CallbackInputStream( 6 | val stream: InputStream, 7 | val callback: StreamCallback? 8 | ) : InputStream() { 9 | 10 | override fun read(): Int { 11 | return stream.read() 12 | } 13 | 14 | override fun read(b: ByteArray?): Int { 15 | return stream.read(b) 16 | } 17 | 18 | override fun read(b: ByteArray?, off: Int, len: Int): Int { 19 | return stream.read(b, off, len) 20 | } 21 | 22 | override fun skip(n: Long): Long { 23 | return stream.skip(n) 24 | } 25 | 26 | override fun available(): Int { 27 | return stream.available() 28 | } 29 | 30 | override fun mark(readlimit: Int) { 31 | stream.mark(readlimit) 32 | } 33 | 34 | override fun reset() { 35 | stream.reset() 36 | } 37 | 38 | override fun markSupported(): Boolean { 39 | return stream.markSupported() 40 | } 41 | 42 | override fun close() { 43 | stream.close() 44 | callback?.onClose() 45 | } 46 | 47 | interface StreamCallback { 48 | fun onClose() 49 | } 50 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/service/impl/net/HttpRequest.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.service.impl.net 2 | 3 | import com.jd.jdcache.service.base.NetState 4 | import com.jd.jdcache.util.JDCacheLog.e 5 | import com.jd.jdcache.util.UrlHelper.METHOD_HEAD 6 | import com.jd.jdcache.util.log 7 | import java.io.BufferedReader 8 | import java.io.IOException 9 | import java.io.InputStream 10 | import java.io.InputStreamReader 11 | import java.lang.StringBuilder 12 | import java.net.HttpURLConnection 13 | import kotlin.Exception 14 | 15 | class HttpRequest(url: String) : BaseRequest(url) { 16 | 17 | override val TAG: String = "HttpRequest" 18 | 19 | @Suppress("BlockingMethodInNonBlockingContext") 20 | override suspend fun parseData( 21 | responseCode: Int, 22 | responseHeaders: Map>?, 23 | contentLength: Long, 24 | inputStream: InputStream? 25 | ): NetState { 26 | var result: StringBuilder? = null 27 | var br: BufferedReader? = null 28 | if (method != METHOD_HEAD && inputStream != null) { 29 | result = StringBuilder() 30 | br = BufferedReader(InputStreamReader(inputStream)) 31 | try { 32 | var readLine: String? 33 | while (br.readLine().also { readLine = it } != null) { 34 | result.append(readLine) 35 | result.append("\n") 36 | } 37 | } catch (e: Exception) { 38 | return NetState.Error(-1, e) 39 | } 40 | } 41 | val netResult = if (responseCode == HttpURLConnection.HTTP_OK) { 42 | NetState.Complete( 43 | responseCode, 44 | responseHeaders, 45 | contentLength, 46 | result?.toString() ?: "") 47 | } else { 48 | NetState.Error(responseCode, Exception(br?.toString() ?: "")) 49 | } 50 | try { 51 | if (br != null) { 52 | br.close() 53 | } else inputStream?.close() 54 | } catch (e: IOException) { 55 | log { e(TAG, e) } 56 | } 57 | disconnect() 58 | return netResult 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/CancellableJob.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | import androidx.annotation.Keep 4 | import kotlinx.coroutines.CancellationException 5 | import kotlinx.coroutines.Job 6 | 7 | @Keep 8 | class CancellableJob(private val job: Job?) : ICancellable{ 9 | 10 | override fun cancel(msg: String?) { 11 | if (job?.isCompleted == false) { 12 | val exMsg = if (msg.isNullOrEmpty()) { 13 | "" 14 | } else { 15 | " Msg: $msg" 16 | } 17 | job.cancel(CancellationException("Job canceled manually.$exMsg")) 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/CollectionHelper.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | 4 | /** 5 | * List转为不支持key为null的Map。 6 | * getKey为获得map的key的方法。 7 | * 若getKey返回null,则那个item不存进map中。 8 | */ 9 | inline fun > 10 | Collection?.keyNonNullMap(getKey: (V) -> K?): M? { 11 | return if (!this.isNullOrEmpty()) { 12 | val map = M::class.java.newInstance() 13 | this.forEach { value -> 14 | getKey(value)?.let { key -> 15 | map[key] = value 16 | } 17 | } 18 | map 19 | } else { 20 | null 21 | } 22 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/CoroutineHelper.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | import androidx.annotation.Keep 4 | import com.jd.jdcache.JDCacheConstant 5 | import kotlinx.coroutines.* 6 | import kotlin.coroutines.Continuation 7 | 8 | @Keep 9 | object CoroutineHelper { 10 | 11 | // /** 12 | // * 启动协程。 13 | // */ 14 | // fun LifecycleOwner.launchCoroutine( 15 | // block: suspend () -> Unit 16 | // ): Job { 17 | // return launchCoroutine(this.lifecycleScope, block) 18 | // } 19 | 20 | /** 21 | * 启动协程。 22 | * 若没有指定scope则使用全局scope。 23 | */ 24 | fun Any?.launchCoroutine( 25 | scope: CoroutineScope? = JDCacheConstant.applicationScope, 26 | block: suspend () -> Unit 27 | ): Job { 28 | val useScope = scope ?: JDCacheConstant.applicationScope 29 | return useScope.launch { block() } 30 | } 31 | 32 | /** 33 | * 在IO线程中执行。 34 | * 若没有指定scope,则使用当前scope;若指定,则使用指定的scope 35 | */ 36 | suspend fun Any?.runOnIo( 37 | scope: CoroutineScope? = null, 38 | block: suspend () -> T 39 | ): T { 40 | val context = scope?.let { scope.coroutineContext + JDCacheConstant.ioDispatcher } 41 | ?: JDCacheConstant.ioDispatcher 42 | return withContext(context) { block() } 43 | } 44 | 45 | @JvmStatic fun Continuation.onSuccess(data: T) { 46 | resumeWith(Result.success(data)) 47 | } 48 | 49 | @JvmStatic fun Continuation.onFail(throwable: Throwable) { 50 | resumeWith(Result.failure(throwable)) 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/FileHelper.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | import com.jd.jdcache.util.CoroutineHelper.runOnIo 4 | import com.jd.jdcache.util.UrlHelper.getFileNameFromUrl 5 | import com.jd.jdcache.util.JDCacheLog.e 6 | import java.io.File 7 | import java.io.FileNotFoundException 8 | import kotlin.random.Random 9 | 10 | 11 | suspend fun File?.getString(): String? { 12 | return this?.let { 13 | if (!it.exists() || !it.isFile) { 14 | null 15 | } else { 16 | runOnIo { 17 | try { 18 | it.readText() 19 | } catch (e: FileNotFoundException) { 20 | log { e("FileHelper", e) } 21 | null 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | /** 29 | * 根据url获取文件名,若不存在,则手动生成文件名 30 | */ 31 | internal fun String?.generateFileName(): String { 32 | return this?.getFileNameFromUrl().let { 33 | val randomStr = "${System.currentTimeMillis()}${Random.nextInt(900) + 100}" 34 | if (it.isNullOrEmpty()) { 35 | randomStr 36 | } else { 37 | "${it}_${randomStr}" 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/ICancellable.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | import androidx.annotation.Keep 4 | 5 | @Keep 6 | interface ICancellable { 7 | fun cancel(msg: String? = null) 8 | } -------------------------------------------------------------------------------- /android/JDCache/src/main/java/com/jd/jdcache/util/IUsefulCheck.kt: -------------------------------------------------------------------------------- 1 | package com.jd.jdcache.util 2 | 3 | fun ?> R.useful(needUseful: Boolean = true): R { 4 | return this?.let { 5 | val iterator = iterator() 6 | while (iterator.hasNext()){ 7 | if ((needUseful && !iterator.next().useful()) 8 | || (!needUseful && iterator.next().useful())) { 9 | iterator.remove() 10 | } 11 | } 12 | return it 13 | } ?: this 14 | } 15 | 16 | //fun ?> R.useful(needUseful: Boolean = true): R { 17 | // return this?.let { 18 | // val iterator = iterator() 19 | // while (iterator.hasNext()) { 20 | // if ((needUseful && !iterator.next().value.useful()) 21 | // || (!needUseful && iterator.next().value.useful())) { 22 | // iterator.remove() 23 | // } 24 | // } 25 | // return it 26 | // } ?: this 27 | //} 28 | 29 | interface IUsefulCheck { 30 | fun useful(): Boolean 31 | } -------------------------------------------------------------------------------- /android/JDWebView/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android/JDWebView/README.md: -------------------------------------------------------------------------------- 1 | # JDWebView - Android 2 | 3 | ## 依赖 4 | 5 | Gradle 6 | 7 | 项目 `build.gradle` 8 | 9 | ```groovy 10 | allprojects { 11 | repositories { 12 | ... 13 | maven { url 'https://jitpack.io' } 14 | } 15 | } 16 | ``` 17 | 18 | 模块 `build.gradle` 19 | 20 | ```groovy 21 | implementation 'com.github.JDFED.JDHybrid:JDWebView:1.0.0' 22 | ``` 23 | 24 | ## 使用 25 | 26 | ### WebView 27 | 28 | 使用 `JDWebView` 作为您的Web View。 29 | 30 | > ```kotlin 31 | > import com.jd.hybrid.JDWebView 32 | > 33 | > ... 34 | > 35 | > val webView = JDWebView(context) 36 | > 37 | > ... 38 | > ``` 39 | 40 | ## 能力 41 | 42 | ### JDBridge 43 | 44 | 已集成 [JDBridge](../JDBridge/README.md) 45 | 46 | ### 生命周期事件 47 | 48 | `JDWebView` 的生命周期变化时会发射以下JS事件: 49 | 50 | - onStart -> event: ContainerShow 51 | 52 | - onResume -> event: ContainerActive 53 | 54 | - onPause -> event: ContainerInactive 55 | 56 | - onStop -> event: ContainerHide 57 | 58 | ### 以下方法会在主线程执行 59 | 60 | `JDWebView`的以下方法将会自动切换到主线程执行,您无需手动切换: 61 | 62 | - addJavascriptInterface 63 | - evaluateJavascript 64 | - loadUrl 65 | - reload 66 | - stopLoading 67 | - goBack 68 | - goForward 69 | - goBackOrForward -------------------------------------------------------------------------------- /android/JDWebView/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.library' 3 | id 'kotlin-android' 4 | id 'maven-publish' 5 | } 6 | 7 | android { 8 | compileSdkVersion 31 9 | 10 | defaultConfig { 11 | minSdkVersion 18 12 | targetSdkVersion 31 13 | 14 | consumerProguardFiles "consumer-rules.pro" 15 | } 16 | 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | compileOptions { 24 | sourceCompatibility JavaVersion.VERSION_1_8 25 | targetCompatibility JavaVersion.VERSION_1_8 26 | } 27 | } 28 | 29 | dependencies { 30 | 31 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 32 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$ktCoroutineVer" 33 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$ktCoroutineVer" 34 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$ktCoroutineVer" 35 | implementation 'androidx.annotation:annotation:1.1.0' 36 | 37 | api project(':JDBridge') 38 | api project(':JDCache') 39 | 40 | } 41 | 42 | publishing { 43 | publications { 44 | release(MavenPublication) { 45 | groupId = 'com.jd.libs' 46 | artifactId = "$artifactId" 47 | version = "$version" 48 | 49 | afterEvaluate { 50 | from components.release 51 | } 52 | } 53 | // debug(MavenPublication) { 54 | // groupId = 'com.jd.libs' 55 | // artifactId = "$artifactId" 56 | // version = "$version-SNAPSHOT" 57 | // 58 | // afterEvaluate { 59 | // from components.debug 60 | // } 61 | // } 62 | } 63 | } -------------------------------------------------------------------------------- /android/JDWebView/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/JDWebView/consumer-rules.pro -------------------------------------------------------------------------------- /android/JDWebView/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | #org.gradle.jvmargs=-Xmx2048m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | artifactId=jdwebview 18 | version=1.0.0 19 | 20 | -------------------------------------------------------------------------------- /android/JDWebView/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android/JDWebView/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | maven { url 'https://jitpack.io' } 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.3' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" 11 | classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion" 12 | // classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4.9.0" 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | maven { url 'https://jitpack.io' } 21 | google() 22 | mavenCentral() 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } -------------------------------------------------------------------------------- /android/example/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /android/example/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'org.jetbrains.kotlin.android' 4 | } 5 | 6 | android { 7 | compileSdkVersion 31 8 | 9 | defaultConfig { 10 | applicationId "com.jd.hybrid.example" 11 | minSdkVersion 21 12 | targetSdkVersion 31 13 | versionCode 1 14 | versionName "1.0" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility JavaVersion.VERSION_1_8 26 | targetCompatibility JavaVersion.VERSION_1_8 27 | } 28 | kotlinOptions { 29 | jvmTarget = '1.8' 30 | } 31 | } 32 | 33 | dependencies { 34 | 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 36 | implementation 'androidx.appcompat:appcompat:1.4.2' 37 | // implementation 'androidx.fragment:fragment-ktx:1.5.0' 38 | implementation 'com.google.android.material:material:1.6.1' 39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 40 | 41 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$ktCoroutineVer" 42 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$ktCoroutineVer" 43 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$ktCoroutineVer" 44 | api project(':JDWebView') 45 | 46 | 47 | } -------------------------------------------------------------------------------- /android/example/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles SETTING_DATA in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android/example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/3jmVvVWpsmP2m1Uab14H8crExDVw/resource.json: -------------------------------------------------------------------------------- 1 | [{"filename":"hHCmZmSi.js","originUrl":"https://wl.jd.com/unify.min.js","url":"https://wl.jd.com/unify.min.js","type":"script","header":{"content-type":"application/javascript","access-control-allow-origin":"*","timing-allow-origin":"*"}},{"filename":"b9SI42oS.js","originUrl":"https://storage11.360buyimg.com/babelnode/jd-jssdk/1.0.0/jd-jssdk.min.js?jdhybrid-offline=1","url":"https://storage11.360buyimg.com/babelnode/jd-jssdk/1.0.0/jd-jssdk.min.js","type":"script","header":{"content-type":"application/x-javascript","content-length":"150075","access-control-allow-origin":"*","timing-allow-origin":"*"}}] 2 | -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/0bH8Cy_E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/0bH8Cy_E.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/16dlwLEK.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/16dlwLEK.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/1TcubCmk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/1TcubCmk.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/35j30APx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/35j30APx.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/6f50yYVd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/6f50yYVd.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/CRQluKky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/CRQluKky.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/Dz37ugM_.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/Dz37ugM_.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/GSCmQFjj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/GSCmQFjj.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/Gn_eGPZO.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/Gn_eGPZO.ttf -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/Libpn-Ov.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/Libpn-Ov.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/Lr3gFskU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/Lr3gFskU.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/M_AMl2pj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/M_AMl2pj.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/PkRd2G0Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/PkRd2G0Z.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/SWYlvsuZ.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/SWYlvsuZ.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/TnTW3zZp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/TnTW3zZp.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/UaDZq_Qh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/UaDZq_Qh.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/Yjd75DCK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/Yjd75DCK.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/dB4FUumh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/dB4FUumh.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/dlq9hIMc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/dlq9hIMc.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/ffFsGIMV.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/ffFsGIMV.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/gTcj0J6H.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/gTcj0J6H.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/hdGhsmA-.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/hdGhsmA-.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/ia-flqdP.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/ia-flqdP.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/inT1ic0d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/inT1ic0d.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/o9aeWBqU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/o9aeWBqU.png -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/tU6yITBB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/tU6yITBB.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/uybpB_BU.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/uybpB_BU.jpg -------------------------------------------------------------------------------- /android/example/src/main/assets/offline/m.jd.com/yn-BEciX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/assets/offline/m.jd.com/yn-BEciX.jpg -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import androidx.fragment.app.Fragment 28 | 29 | abstract class BaseFragment : Fragment() { 30 | lateinit var perfData: Utils.PerformanceData 31 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/CoroutineHelper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import kotlinx.coroutines.* 28 | 29 | object CoroutineHelper { 30 | 31 | /** 32 | * 启动协程。 33 | * 若没有指定scope则使用全局scope。 34 | */ 35 | fun Any?.launchCoroutine( 36 | scope: CoroutineScope? = XConstant.applicationScope, 37 | block: suspend () -> Unit 38 | ): Job { 39 | val useScope = scope ?: XConstant.applicationScope 40 | return useScope.launch { block() } 41 | } 42 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/GlobalJdBridgePlugin.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import com.jd.jdbridge.base.IBridgeCallback 28 | import com.jd.jdbridge.base.IBridgePlugin 29 | import com.jd.jdbridge.base.IBridgeWebView 30 | 31 | class GlobalJdBridgePlugin : IBridgePlugin { 32 | companion object { 33 | const val NAME = "GlobalJdBridgePlugin" 34 | } 35 | 36 | override fun execute( 37 | webView: IBridgeWebView?, 38 | method: String?, 39 | params: String?, 40 | callback: IBridgeCallback? 41 | ): Boolean { 42 | showToast("GlobalJdBridgePlugin called by js, params = $params") 43 | callback?.onSuccess("ok") 44 | return true 45 | } 46 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/MyApplication.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import android.app.Application 28 | import android.widget.Toast 29 | import com.jd.hybrid.JDWebView 30 | import com.jd.hybrid.example.CoroutineHelper.launchCoroutine 31 | import com.jd.jdbridge.JDBridgeManager 32 | import com.jd.jdcache.JDCache 33 | import kotlinx.coroutines.Dispatchers 34 | import kotlinx.coroutines.withContext 35 | 36 | fun Any.showToast(msg: String?){ 37 | msg?.apply { 38 | launchCoroutine { 39 | withContext(Dispatchers.Main.immediate) { 40 | Toast.makeText(MyApplication.app, msg, Toast.LENGTH_SHORT).show() 41 | } 42 | } 43 | } 44 | } 45 | 46 | class MyApplication : Application() { 47 | 48 | companion object { 49 | lateinit var app: Application 50 | private set 51 | var userAgent: String? = null 52 | var debug = true 53 | } 54 | 55 | override fun onCreate() { 56 | app = this 57 | super.onCreate() 58 | 59 | JDWebView.webDebug = debug // will also set JDBridge.js debuggable 60 | //初始化JDCache 61 | JDCache.init(this, debug) 62 | //设置必要参数 63 | JDCache.setGlobalParams(MyHybridParamsProvider::class.java) 64 | //注册全局JS桥 65 | JDBridgeManager.registerPlugin(GlobalJdBridgePlugin.NAME, GlobalJdBridgePlugin::class.java) 66 | } 67 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/MyMatcher.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import android.webkit.WebResourceRequest 28 | import android.webkit.WebResourceResponse 29 | import com.jd.jdcache.match.base.JDCacheResourceMatcher 30 | import com.jd.jdcache.util.JDCacheLog 31 | 32 | class MyMatcher : JDCacheResourceMatcher() { 33 | override val name: String = "MyMatcher" 34 | 35 | override fun match(request: WebResourceRequest): WebResourceResponse? { 36 | if (request.isForMainFrame) { 37 | JDCacheLog.d("MyMatcher test matching") 38 | showToast("Custom Matcher matching") 39 | } 40 | return null 41 | } 42 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/MyWebView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import android.content.Context 28 | import android.os.Build 29 | import android.util.AttributeSet 30 | import androidx.annotation.RequiresApi 31 | import com.jd.hybrid.JDWebView 32 | 33 | class MyWebView : JDWebView { 34 | constructor(context: Context) 35 | : super(context) 36 | 37 | constructor(context: Context, attrs: AttributeSet?) 38 | : super(context, attrs) 39 | 40 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) 41 | : super(context, attrs, defStyleAttr) 42 | 43 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 44 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) 45 | : super(context, attrs, defStyleAttr, defStyleRes) 46 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/PerfDialogFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import android.os.Bundle 28 | import android.view.LayoutInflater 29 | import android.view.View 30 | import android.view.ViewGroup 31 | import android.widget.TextView 32 | import androidx.fragment.app.DialogFragment 33 | 34 | class PerfDialogFragment : DialogFragment() { 35 | 36 | var perfData: Utils.PerformanceData? = null 37 | 38 | override fun onCreateView( 39 | inflater: LayoutInflater, 40 | container: ViewGroup?, 41 | savedInstanceState: Bundle? 42 | ): View? { 43 | val view = inflater.inflate(R.layout.dialog_performance, container, false) 44 | view.findViewById(R.id.close).setOnClickListener { 45 | dismiss() 46 | } 47 | return view 48 | } 49 | 50 | override fun onResume() { 51 | super.onResume() 52 | perfData?.let { 53 | view?.findViewById(R.id.tvPerfData)?.text = it.toString() 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/Setting.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import com.jd.jdcache.JDCache 28 | 29 | 30 | object Setting { 31 | 32 | var settingData: SettingData = SettingData() 33 | 34 | data class SettingData( 35 | var enableJDCache: Boolean = true, 36 | var preloadHtml: Boolean = true, 37 | var useCustomMatcher: Boolean = false, 38 | var urlIndex: Int = 0, 39 | var url: String = MyApplication.app.getString(R.string.settings_url0) 40 | ) { 41 | init { 42 | JDCache.enable(enableJDCache) 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/WebActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import android.os.Bundle 28 | import androidx.appcompat.app.AppCompatActivity 29 | 30 | class WebActivity : AppCompatActivity() { 31 | 32 | private lateinit var fragment: BaseFragment 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | setContentView(R.layout.activity_web) 37 | createFragment() 38 | } 39 | 40 | private fun createFragment() { 41 | val fragment = when (intent.getStringExtra("pageType")) { 42 | "system" -> SysWebFragment() 43 | "JDCache" -> JDCacheFragment() 44 | "JDBridge" -> JDBridgeFragment() 45 | else -> null 46 | } 47 | fragment?.let { 48 | it.arguments = intent.extras 49 | this.fragment = it 50 | val ft = supportFragmentManager.beginTransaction() 51 | ft.add(R.id.fragment_container, fragment).commit() 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /android/example/src/main/java/com/jd/hybrid/example/XConstant.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022 JD.com, Inc. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | package com.jd.hybrid.example 26 | 27 | import kotlinx.coroutines.CoroutineScope 28 | import kotlinx.coroutines.SupervisorJob 29 | 30 | object XConstant { 31 | internal val applicationScope by lazy { CoroutineScope(SupervisorJob()) } 32 | } -------------------------------------------------------------------------------- /android/example/src/main/res/drawable-hdpi/ic_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/drawable-hdpi/ic_settings.png -------------------------------------------------------------------------------- /android/example/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /android/example/src/main/res/layout/activity_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /android/example/src/main/res/layout/dialog_performance.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 22 | 29 | 30 | -------------------------------------------------------------------------------- /android/example/src/main/res/layout/fragment_jdcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /android/example/src/main/res/layout/fragment_sys_webview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /android/example/src/main/res/layout/fragment_xcache.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /android/example/src/main/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jd-opensource/JDHybrid/7876f326a966d359b0139cc80ffe292045d089b7/android/example/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/example/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /android/example/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | #FF039BE5 11 | #FF01579B 12 | #FF40C4FF 13 | #FF00B0FF 14 | #66000000 15 | -------------------------------------------------------------------------------- /android/example/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | -------------------------------------------------------------------------------- /android/example/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | JDHybrid 3 | JDHybrid 4 | WebViewActivity 5 | Settings 6 | 7 | file:///android_asset/jdbridge_demo.html 8 | https://m.jd.com 9 | https://prodev.m.jd.com/mall/active/3jmVvVWpsmP2m1Uab14H8crExDVw/index.html 10 | -------------------------------------------------------------------------------- /android/example/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /android/example/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 24 | 25 | 29 | 30 |