react-native-code-sync
Version:
React-native plugin for the code-sync functionality on live via OTA (Over-the-air)
193 lines (179 loc) • 7.83 kB
JavaScript
import { useMemo } from 'react';
import { Platform } from 'react-native';
import ReactNativeBlobUtil from 'react-native-blob-util';
import { unzip } from 'react-native-zip-archive'
import RNFS from 'react-native-fs';
import { Utility } from '../utils'
import OtaApiConstant from './OtaApiConstant.json';
const OTA_ROOT_PATH = RNFS.DocumentDirectoryPath
export const useCheckVersion = () => {
const bundleFileName = useMemo(() => {
return Platform.select({ android: 'index.android.bundle', ios: 'main.jsbundle' })
}, [])
const installFail = (message) => Utility.log("Update failed:", message);
const downloadBundleFile = async (uri, downloadProgress) => {
if (!uri) return '';
const filename = uri.split('/').pop();
const downloadPath = `${OTA_ROOT_PATH}/${filename}`;
try {
const downloadResult = await RNFS.downloadFile({
fromUrl: uri, toFile: downloadPath,
begin: res => { },
progress: res => {
const progressPercent = (res.bytesWritten / res.contentLength) * 100;
downloadProgress?.(progressPercent);
}
}).promise;
return downloadResult.statusCode === 200 ? downloadPath : '';
} catch (error) {
Utility.log("Download error:", error);
return '';
}
};
const deleteOldBundleIfNeeded = async () => {
const filePath = `${OTA_ROOT_PATH}/${bundleFileName}`;
const fileExists = await Utility.checkFileExists(filePath);
if (fileExists) {
try {
await ReactNativeBlobUtil.fs.unlink(filePath);
return true;
} catch (error) {
Utility.log("Error deleting old bundle:", error);
}
}
return false;
};
const extractZipFile = async (zipFilePath = '') => {
if (!zipFilePath) return false;
try {
const extractedPath = `${OTA_ROOT_PATH}/${Date.now()}`;
await unzip(zipFilePath, extractedPath);
const files = await ReactNativeBlobUtil.fs.ls(extractedPath);
if (files?.length) {
const androidDirectoryName = 'output'
if (!files?.includes(androidDirectoryName)) return false
const outputfiles = `${extractedPath}/${androidDirectoryName}`
const outputDirectoryFiles = await ReactNativeBlobUtil.fs.ls(outputfiles);
if (outputDirectoryFiles.includes(bundleFileName)) {
await deleteOldBundleIfNeeded();
return await moveBundleFile(outputfiles, [extractedPath, zipFilePath], outputDirectoryFiles);
}
}
}
catch (error) {
Utility.log("Unzip error:", error);
}
return false
}
const moveBundleFile = async (extractedPath, filesToDelete = [], bundleFiles = []) => {
try {
for (const element of bundleFiles) {
const completetargetPath = `${OTA_ROOT_PATH}/${element}`
const completeExtractedPath = `${extractedPath}/${element}`
if (await Utility.checkFileExists(completetargetPath)) {
await ReactNativeBlobUtil.fs.unlink(completetargetPath)
}
if (await Utility.checkFileExists(completeExtractedPath)) {
await ReactNativeBlobUtil.fs.mv(completeExtractedPath, completetargetPath);
}
}
await Promise.all(filesToDelete.map(path => ReactNativeBlobUtil.fs.unlink(path)));
return true;
} catch (error) {
Utility.log("Move file error:", error);
}
return false;
};
const setupBundlePath = async (path, curentbundleVersion, onUpdateComplete, onUpdateFailed) => {
try {
if (!path || !(await extractZipFile(path))) {
onUpdateFailed?.();
return;
}
const otaVersionInfo = {
ota_version_code: curentbundleVersion?.toString(),
ota_app_version: Utility.getAppVersion()?.toString()
}
Utility.log("otaVersionInfo===>", otaVersionInfo)
Utility.setAsyncStorage({ key: OtaApiConstant.LOCAL_KEYS.OTA_INFO, value: JSON.stringify(otaVersionInfo) })
onUpdateComplete?.();
}
catch (err) {
onUpdateFailed?.()
}
}
const startUpdate = async (url, curentbundleVersion, downloadProgress, onUpdateComplete, onUpdateFailed) => {
try {
if (!url || !curentbundleVersion) return installFail("Invalid URL or version");
// if (!(await Utility.requestStoragePermission())) {
// Utility.showToast('Storage permission not provided');
// onUpdateFailed?.()
// return installFail("Storage permission denied");
// }
const downloadedPath = await downloadBundleFile(url, downloadProgress)
if (downloadedPath) await setupBundlePath(downloadedPath, curentbundleVersion, onUpdateComplete, onUpdateFailed);
else {
onUpdateFailed?.()
}
} catch (error) {
Utility.log("Update error:", error);
onUpdateFailed?.()
}
}
const checkForUpgradedAppVersionAvailable = async () => {
if (Utility.checkForDevMode()) return
const otaInfo = await Utility.getAsyncStorage({ key: OtaApiConstant.LOCAL_KEYS.OTA_INFO })
let previousAppVersion = null
if (otaInfo) {
const parsedOTAInfo = JSON.parse(otaInfo)
previousAppVersion = parsedOTAInfo.ota_app_version
}
const installedAppVersion = Utility.getAppVersion()
const convertedInstalledAppVersion = Number(installedAppVersion?.toString().replace(/\./g, ''))
const convertedPreviousAppversion = Number(previousAppVersion?.toString().replace(/\./g, ''))
if (convertedInstalledAppVersion > convertedPreviousAppversion) {
await deleteOldBundleIfNeeded()
const otaVersionInfo = {
ota_version_code: '0',
ota_app_version: installedAppVersion?.toString()
}
Utility.setAsyncStorage({ key: OtaApiConstant.LOCAL_KEYS.OTA_INFO, value: JSON.stringify(otaVersionInfo) })
Utility.reloadApp()
return
}
}
const onCheckVersion = async ({
bundleUrl = '',
curentbundleVersion = '',
serverAppVersion = '',
onStartUpdate = () => { },
downloadProgress = () => { },
onUpdateComplete = () => { },
onUpdateFailed = () => { },
onUpdateNotAvailable = () => { }
}) => {
if (Utility.checkForDevMode()) return onUpdateNotAvailable?.()
const otaInfo = await Utility.getAsyncStorage({ key: OtaApiConstant.LOCAL_KEYS.OTA_INFO })
let previousVersion = null, previousAppVersion = null, installedAppVersion = Utility.getAppVersion()
if (otaInfo) {
const parsedOTAInfo = JSON.parse(otaInfo)
previousVersion = parsedOTAInfo.ota_version_code
previousAppVersion = parsedOTAInfo.ota_app_version
}
if (curentbundleVersion > previousVersion && serverAppVersion == installedAppVersion) {
onStartUpdate?.(true);
startUpdate(
bundleUrl,
curentbundleVersion,
downloadProgress,
onUpdateComplete,
onUpdateFailed
)
}
else onUpdateNotAvailable?.()
};
return {
onCheckVersion,
checkForUpgradedAppVersionAvailable
};
}