offline_webview 1.2.0
offline_webview: ^1.2.0 copied to clipboard
A lightweight high-performance Flutter SDK for offline web package loading with URL matching, flow pipeline, WebView integration, monitoring and reporting. Supports iOS/Android.
简体中文 | English
offline_webview #
A lightweight high-performance Flutter SDK for offline web package loading.
Features #
- Offline Package Management: Download, cache, and serve web resources locally
- URL Matching: Flexible rule-based URL to bisName matching (param mode & rule mode)
- Flow Pipeline: Extensible chain-of-responsibility processing pipeline
- WebView Integration: Seamless InAppWebView (iOS/Android) integration with screenshot cache and vConsole
- Performance Monitor: Built-in debug floating panel showing loading timeline comparison
- Monitoring & Reporting: Built-in logging, monitoring, and data reporting
- Local Server: Per-package HTTP server on localhost, serving resources without file:// hacks
- Fastlane CI/CD: One-command build & distribute to Pgyer for iOS/Android
Installation #
dependencies:
offline_webview: ^1.1.0
Quick Start #
1. Start the test server #
cd tool
python3 server.py
# Server auto-detects LAN IP and runs at http://<your-lan-ip>:18730
2. Initialize the SDK #
import 'package:offline_webview/offline_webview.dart';
// Build config (preDownloadAll downloads all available packages from server)
final config = OfflineConfigBuilder()
.isOpen(true)
.preDownloadAll(true)
.build();
// Build params
final params = OfflineParams()
.config(config)
.isDebug(true)
.logBlock((level, message) => print(message))
.reportBlock((event, bisName, params) => print('Report: $event'))
.monitorBlock((type, data) => print('Monitor: $type'))
.requestServer(YourRequest());
await OfflineWebClient.init(params);
3. Use OfflineWebView #
// Param mode: URL contains ?offweb=bisName
OfflineWebView(
initialUrl: 'https://example.com/page?offweb=my-bis-name',
enableVConsole: true, // inject vConsole debug panel
)
// With controller for reload
final controller = OfflineWebViewController();
OfflineWebView(
initialUrl: 'https://example.com/page?offweb=my-bis-name',
controller: controller,
onLoadTiming: (totalMs) => print('Loaded in ${totalMs}ms'),
)
// Reload offline web
controller.reloadOfflineWeb();
4. Implement IOfflineRequest #
class YourRequest extends IOfflineRequest {
@override
void requestPackageInfo(
String bisName,
String version,
RequestCallback<OfflinePackageInfo> callback,
) async {
final url = Uri.parse('http://your-server:18730/offweb').replace(
queryParameters: {'bisName': bisName, 'offlineZipVer': version},
);
final response = await http.get(url);
final json = jsonDecode(response.body);
callback.onSuccess(OfflinePackageInfo.fromJson(json));
}
@override
void requestAllBisNames(RequestCallback<List<String>> callback) async {
final response = await http.get(Uri.parse('http://your-server:18730'));
final json = jsonDecode(response.body);
final packages = (json['packages'] as List).map((e) => e.toString()).toList();
callback.onSuccess(packages);
}
}
Creating Offline Packages #
An offline package is a standard .zip file containing your web resources and a version manifest.
Package structure #
my-package.zip
├── .offweb.json # Required: version manifest
├── index.html # Entry point
├── css/
│ └── style.css
├── js/
│ └── app.js
└── images/
└── logo.png
Version manifest (.offweb.json) #
Place this file at the root of the zip:
{
"bisName": "my-package",
"version": "v1"
}
Requirements #
.offweb.jsonmust exist at the zip root withbisNameandversionfieldsindex.htmlmust exist as the entry point- All resource paths (CSS, JS, images) should use relative paths
- H5 pages must support null-origin for cookie/storage (loaded from
localhost)
Upload to server #
Place the zip file in the server's packages/ directory, or use the built-in upload page at http://<server-ip>:18730/upload.
Server query API #
When the SDK queries the server, the response format is:
{
"bisName": "my-package",
"result": 1,
"url": "http://server:18730/package?bisName=my-package",
"refreshMode": 0,
"version": "v2"
}
| Field | Description |
|---|---|
result |
-1 = disabled, 0 = same version, 1 = update available |
url |
Download URL for the zip package |
refreshMode |
0 = normal, 1 = force refresh |
version |
Latest version string |
URL Matching #
Param mode #
Append ?offweb=<bisName> to the URL. The SDK automatically intercepts it:
OfflineWebView(
initialUrl: 'https://example.com/page?offweb=my-bis-name',
)
Rule mode #
Configure OfflineRuleConfig to match URLs by host/path patterns without modifying the URL:
final params = OfflineParams()
.config(OfflineConfigBuilder().isOpen(true).build())
.setRule(OfflineRuleConfig(
rules: [
OfflineRuleItem(host: 'example.com', path: '/app/*', bisName: 'my-app'),
],
))
.requestServer(YourRequest());
Performance Monitor #
The SDK includes a debug-mode performance monitor with a draggable floating panel:
FloatingPerformancePanel(
child: OfflineWebView(initialUrl: '...'),
)
// Or standalone (OfflineWebView embeds it internally)
FloatingPerformancePanel()
| Metric | Description |
|---|---|
webViewCreatedMs |
Time from widget creation to WebView ready |
firstPaintMs |
Time to first visual paint |
loadCompleteMs |
Time to page fully loaded |
queryMs |
Offline query phase (offline mode only) |
downloadMs |
Package download phase (offline mode only) |
unzipMs |
Package extraction phase (offline mode only) |
Color coding: green (<50ms), blue (<200ms), yellow (<500ms), red (>=500ms).
Configuration #
final config = OfflineConfigBuilder()
.isOpen(true) // Enable/disable offline feature
.preDownloadAll(true) // Pre-download all packages from server
.addPreDownload('bis-name-1') // Pre-download specific packages
.addPreDownload('bis-name-2')
.addDisable('bis-name-3') // Disable specific packages
.build();
Local Development Server #
A Python HTTP server is provided for local testing:
cd tool
python3 server.py
Server endpoints:
GET /- Server info & registered packagesGET /health- Health checkGET /offweb?bisName=xxx&offlineZipVer=xxx- Query package updateGET /package?bisName=xxx- Download package zipGET /upload- Web upload pagePOST /upload- Upload zip packageGET /demo- Demo HTML page
Architecture #
+-------------------------------------------------------------+
| OfflineWebClient |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| OfflineWebManager |
+-------------------------------------------------------------+
|
+-------------+-------------+
| |
v v
+---------------------------+ +-----------------------------+
| ResourceFlow Pipeline | | PerformanceMonitor |
| FetchPackageFlow | | (singleton, Stream-based) |
| -> DownloadFlow | | ↳ FloatingPerformancePanel |
| -> ParsePackageFlow | +-----------------------------+
| -> ReplaceResFlow |
+---------------------------+
|
v
+-------------------------------------------------------------+
| OfflineWebView |
| (InAppWebView + LocalServer + WebViewPreloadPool) |
+-------------------------------------------------------------+
CI/CD with Fastlane #
bundle install
# Build & upload iOS
bundle exec fastlane build_ios
# Build & upload Android
bundle exec fastlane build_android
Platform Support #
- iOS (InAppWebView / WKWebView)
- Android (InAppWebView / WebView)
- Flutter Web (limited)
License #
MIT License - see LICENSE file