记下来,省的下次忘了
使用 On Demand Resources File 的目的是使用App Store托管资源文件,但是又不想增加“下载大小”,避免用户看到资源太大不愿意下载App。
1、添加资源文件到项目里
注意不要直接复制到目录里,要在xcode里面操作,不然不能被项目识别
2、设置Tag标签,设置为按需下载类型
Tag是获取下载的标签,要注意这个名字
Debug模式不支持从App Store下载资源,所以要设置Debug为包含资源
3、写原生方法下载资源
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel.init(name: "com.example.odr", binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
if (call.method == "requestODR") {
self.requestODR(call, result)
}
if (call.method == "requestODRFile") {
self.loadFile(call: call, result: result)
}
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
///
/// 请求ODR标签数据
///
func requestODR(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
let tag = call.arguments as! String
let tagsSet: Set<String> = [tag]
let request = NSBundleResourceRequest(tags: tagsSet, bundle: Bundle.main)
request.conditionallyBeginAccessingResources { hasCache in
if hasCache == false {
// 这些资源不全在本地
request.beginAccessingResources { error in
if let _ = error {
// 下载失败
print("[ORGIN]Download Failed");
result("404 \(String(describing: error))");
}
else {
// 下载成功
print("[ORGIN]Download Success");
result("200");
}
}
}
else {
// 这些资源已经在本地了
result("301");
}
}
}
///
/// 暴露数据给Flutter
///
func loadFile(call: FlutterMethodCall, result: @escaping FlutterResult) {
let fileName = call.arguments as! String;
print(Bundle.main.bundlePath)
print(fileName)
let path = Bundle.main.path(forResource: fileName, ofType: "zip")
if(path != nil){
let data = try! Data(contentsOf: URL(fileURLWithPath: path!))
result(data)
}else{
print("找不到数据")
result("")
}
}
}
4、Flutter端调用
import 'dart:io';
import 'package:archive/archive_io.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
///
/// 从苹果服务器下载字体资源到本地
///
const platform = MethodChannel('com.example.odr');
Future<void> requestODR(String tag) async {
debugPrint("开始下载资源");
try {
dynamic a = await platform.invokeMethod('requestODR', tag);
debugPrint("下载反馈:$a");
if (a == '200' || a == '301') {
await getTagSource('cz_font');
} else {
tipBar('$a', time: 30);
}
} on PlatformException catch (e) {
debugPrint("$e");
tipBar("$e", title: "测试下载错误");
}
}
Future<void> getTagSource(String tagFile) async {
/// requestODRFile
try {
Uint8List data = await platform.invokeMethod('requestODRFile', tagFile);
await loadZipAndRegisterFont(data);
///
box.put(Config.fontDownload, Config.fontVersion);
} catch (e) {
debugPrint("$e");
tipBar("$e", title: "文件异常");
}
}
///
/// 读取ZIP文件、解压
///
Future<void> loadZipAndRegisterFont(Uint8List data) async {
/// 字体目录
Directory doc = await getApplicationDocumentsDirectory();
Directory docuPath = Directory('${doc.path}/source/vip_fonts');
bool exists = await docuPath.exists();
if (!exists) {
debugPrint(">>>新建该目录 ${docuPath.path}");
await docuPath.create(recursive: true);
}
final archive = ZipDecoder().decodeBytes(data);
// For all of the entries in the archive
for (var file in archive.files) {
// If it's a file and not a directory
if (file.isFile) {
// Write the file content to a directory called 'out'.
// In practice, you should make sure file.name doesn't include '..' paths
// that would put it outside of the extraction directory.
// An OutputFileStream will write the data to disk.
final outputStream = OutputFileStream('${docuPath.path}/${file.name}');
// The writeContent method will decompress the file content directly to disk without
// storing the decompressed data in memory.
file.writeContent(outputStream);
// Make sure to close the output stream so the File is closed.
outputStream.close();
}
}
}