import 'dart:typed_data'; import 'package:http/http.dart'; import 'package:pkpass/pkpass.dart'; import 'package:pkpass/pkpass_web_wervice/utils/http_date.dart'; import 'web_service_error.dart'; /// PassKit WebService implementation /// /// A Representational State Transfer (REST)–style web service protocol is used /// to communicate with your server about changes to passes, and to fetch the /// latest version of a pass when it has changed. /// /// https://developer.apple.com/library/archive/documentation/PassKit/Reference/PassKit_WebService/WebService.html#//apple_ref/doc/uid/TP40011988 class PkPassWebService { static const _apiVersion = 'v1'; static Client? _client; /// The [PassMetadata] to check for updates. final PassMetadata metadata; /// An optional [Client] used for any http requests final Client? client; const PkPassWebService(this.metadata, {this.client}); PassWebService get webService { final service = metadata.webService; if (service == null) noWebServiceProvided(); return service; } Client get httpClient { final client = this.client; if (client != null) return client; return _client ??= Client(); } /// Getting the Latest Version of a Pass /// /// Requests the latest version of the current PkPass file /// /// [modifiedSince] should be provided in order to support "304 Not Modified" Future getLatestVersion([DateTime? modifiedSince]) async { final identifier = metadata.passTypeIdentifier; final serial = metadata.serialNumber; final endpoint = '/$_apiVersion/passes/$identifier/$serial'; final response = await httpClient.get( Uri.parse(webService.webServiceURL.toString() + endpoint), headers: { if (modifiedSince != null) 'If-Modified-Since': HttpDate.format(modifiedSince), 'Authorization': 'ApplePass ${webService.authenticationToken}', }, ); switch (response.statusCode) { case 200: return response.bodyBytes; case 304: return null; default: throw WebServiceResponseError(response); } } Never noWebServiceProvided() => throw WebServiceUnavailable(); }