Skip to content

Instantly share code, notes, and snippets.

@wenshin
Last active December 27, 2021 06:15
Show Gist options
  • Save wenshin/4f5d5f7e680034149ae9590e9d473ab7 to your computer and use it in GitHub Desktop.
Save wenshin/4f5d5f7e680034149ae9590e9d473ab7 to your computer and use it in GitHub Desktop.
/**
* iOS Webview 中,如果通过打开多个 Webview 来打开页面,那么跨页面的 LocalStorage 和 IndexedDB 都不会及时生效。
* 原因见 https://stackoverflow.com/questions/36332208/two-wkwebviews-share-local-storage-but-only-after-restart
* 解决方案:
* 1. 参考修改 iOS Webview 调度逻辑 https://stackoverflow.com/questions/36332208/two-wkwebviews-share-local-storage-but-only-after-restart
* 2. 使用 Native 提供的 Bridge
*/
import { isSupportKVStore, kvGetItem, kvSetItem } from '@/utils/app';
import bridge from '@/utils/bridge';
let dbPromise: Promise<IDBDatabase | null>;
const API_CACHE_TABLE = 'hiii-h5-api-cache';
/**
* 首次打开 db 大概需要 70ms
* @returns
*/
function getDB(): Promise<IDBDatabase | null> {
if (!dbPromise) {
dbPromise = new Promise((resolve) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if (indexedDB) {
const req = indexedDB.open('hiii-h5', 5);
req.onsuccess = () => {
resolve(req.result);
};
req.onerror = (evt) => {
console.log('open index db fail', evt);
resolve(null);
};
req.onupgradeneeded = function onupgradeneeded(evt) {
const db = req.result;
let objectStore;
if (evt.oldVersion < 4) {
if (db.objectStoreNames.contains(API_CACHE_TABLE)) {
db.deleteObjectStore(API_CACHE_TABLE);
}
}
if (!db.objectStoreNames.contains(API_CACHE_TABLE)) {
objectStore = db.createObjectStore(API_CACHE_TABLE, { keyPath: 'key' });
objectStore.createIndex('key', 'key', { unique: true });
}
};
} else {
resolve(null);
}
});
}
return dbPromise;
}
function promisifyIDBRequest<T = null>(req: IDBRequest): Promise<T | null> {
return new Promise((resolve) => {
req.onsuccess = () => {
resolve(req.result);
};
req.onerror = () => {
// 出错,不抛出错误,不阻塞正常流程
console.log('setItem failed');
resolve(null);
};
});
}
interface StoreItem {
key: string,
value: any,
}
export const storageWeb = {
async setItem(name: string, value: any) {
const db = await getDB();
if (db) {
return promisifyIDBRequest(
db.transaction([API_CACHE_TABLE], 'readwrite')
.objectStore(API_CACHE_TABLE)
.put({ key: name, value })
);
} else {
localStorage.setItem(name, JSON.stringify(value));
}
},
async getItem<T>(name: string): Promise<T | null> {
const db = await getDB();
if (db) {
const item = await promisifyIDBRequest<StoreItem>(
db.transaction([API_CACHE_TABLE], 'readwrite')
.objectStore(API_CACHE_TABLE)
.get(name)
);
return item && item.value;
} else {
const str = localStorage.getItem(name);
if (str) {
return Promise.resolve(JSON.parse(str));
} else {
return Promise.resolve(null);
}
}
},
};
export const storage = {
async setItem(name: string, value: any) {
if (bridge.enabled) {
const isSupport = await isSupportKVStore();
if (isSupport) {
kvSetItem(name, value);
} else {
await storageWeb.setItem(name, value);
}
} else {
await storageWeb.setItem(name, value);
}
},
async getItem<T>(name: string): Promise<T | null> {
if (bridge.enabled) {
const isSupport = await isSupportKVStore();
if (isSupport) {
return kvGetItem<T>(name);
} else {
return storageWeb.getItem<T>(name);
}
} else {
return storageWeb.getItem<T>(name);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment