2019-10-26 02:42:50 +00:00
import ' dart:io ' ;
import ' dart:async ' ;
2021-03-18 16:24:13 +00:00
import ' dart:typed_data ' ;
2019-10-26 02:42:50 +00:00
import ' package:flutter/services.dart ' show rootBundle ;
2021-03-01 02:21:07 +00:00
import ' mime_type_resolver.dart ' ;
2019-10-26 02:42:50 +00:00
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
class InAppLocalhostServer {
2021-01-28 16:10:15 +00:00
HttpServer ? _server ;
2019-10-26 02:42:50 +00:00
int _port = 8080 ;
InAppLocalhostServer ( { int port = 8080 } ) {
this . _port = port ;
}
2021-03-23 20:53:42 +00:00
///Starts the server on `http://localhost:[port]/`.
2019-10-26 02:42:50 +00:00
///
///**NOTE for iOS**: For the iOS Platform, you need to add the `NSAllowsLocalNetworking` key with `true` in the `Info.plist` file (See [ATS Configuration Basics](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35)):
///```xml
///<key>NSAppTransportSecurity</key>
///<dict>
/// <key>NSAllowsLocalNetworking</key>
/// <true/>
///</dict>
///```
///The `NSAllowsLocalNetworking` key is available since **iOS 10**.
Future < void > start ( ) async {
if ( this . _server ! = null ) {
throw Exception ( ' Server already started on http://localhost: $ _port ' ) ;
}
2020-05-29 17:56:03 +00:00
var completer = Completer ( ) ;
2019-10-26 02:42:50 +00:00
2021-02-26 10:27:29 +00:00
runZonedGuarded ( ( ) {
2019-10-26 02:42:50 +00:00
HttpServer . bind ( ' 127.0.0.1 ' , _port ) . then ( ( server ) {
print ( ' Server running on http://localhost: ' + _port . toString ( ) ) ;
this . _server = server ;
server . listen ( ( HttpRequest request ) async {
2021-03-18 16:24:13 +00:00
Uint8List body = Uint8List ( 0 ) ;
2019-10-26 02:42:50 +00:00
var path = request . requestedUri . path ;
path = ( path . startsWith ( ' / ' ) ) ? path . substring ( 1 ) : path ;
2019-11-11 09:01:47 +00:00
path + = ( path . endsWith ( ' / ' ) ) ? ' index.html ' : ' ' ;
2019-10-26 02:42:50 +00:00
try {
2019-12-01 11:55:06 +00:00
body = ( await rootBundle . load ( path ) ) . buffer . asUint8List ( ) ;
2019-10-26 02:42:50 +00:00
} catch ( e ) {
print ( e . toString ( ) ) ;
request . response . close ( ) ;
return ;
}
var contentType = [ ' text ' , ' html ' ] ;
2019-12-01 11:55:06 +00:00
if ( ! request . requestedUri . path . endsWith ( ' / ' ) & &
request . requestedUri . pathSegments . isNotEmpty ) {
2021-03-01 02:21:07 +00:00
var mimeType = MimeTypeResolver . lookup ( request . requestedUri . path ) ;
2019-10-26 02:42:50 +00:00
if ( mimeType ! = null ) {
contentType = mimeType . split ( ' / ' ) ;
}
}
2019-12-01 11:55:06 +00:00
request . response . headers . contentType =
2020-05-29 17:56:03 +00:00
ContentType ( contentType [ 0 ] , contentType [ 1 ] , charset: ' utf-8 ' ) ;
2019-10-26 02:42:50 +00:00
request . response . add ( body ) ;
request . response . close ( ) ;
} ) ;
completer . complete ( ) ;
} ) ;
2021-02-26 10:27:29 +00:00
} , ( e , stackTrace ) = > print ( ' Error: $ e $ stackTrace ' ) ) ;
2019-10-26 02:42:50 +00:00
return completer . future ;
}
///Closes the server.
Future < void > close ( ) async {
if ( this . _server ! = null ) {
2021-01-28 16:10:15 +00:00
await this . _server ! . close ( force: true ) ;
2019-10-26 02:42:50 +00:00
print ( ' Server running on http://localhost: $ _port closed ' ) ;
this . _server = null ;
}
}
2019-11-11 09:01:47 +00:00
}