/* * This script generates a hash of all the React Native bundled assets and writes it into * into the APK. The hash in "updateCheck" requests to prevent downloading an identical * update to the one already present in the binary. * * It first creates a snapshot of the contents in the resource directory by creating * a map with the modified time of all the files in the directory. It then compares this * snapshot with the one saved earlier in "recordFilesBeforeBundleCommand.js" to figure * out which files were generated by the "react-native bundle" command. It then computes * the hash for each file to generate a manifest, and then computes a hash over the entire * manifest to generate the final hash, which is saved to the APK's assets directory. */ var crypto = require("crypto"); var fs = require("fs"); var path = require("path"); var getFilesInFolder = require("./getFilesInFolder"); var CODE_PUSH_FOLDER_PREFIX = "CodePush"; var CODE_PUSH_HASH_FILE_NAME = "CodePushHash.json"; var HASH_ALGORITHM = "sha256"; var TEMP_FILE_PATH = path.join(require("os").tmpdir(), "CodePushResourcesMap.json"); var resourcesDir = process.argv[2]; var jsBundleFilePath = process.argv[3]; var assetsDir = process.argv[4]; var resourceFiles = []; getFilesInFolder(resourcesDir, resourceFiles); var oldFileToModifiedTimeMap = require(TEMP_FILE_PATH); var newFileToModifiedTimeMap = {}; resourceFiles.forEach(function(resourceFile) { newFileToModifiedTimeMap[resourceFile.path.substring(resourcesDir.length)] = resourceFile.mtime; }); var bundleGeneratedAssetFiles = []; for (var newFilePath in newFileToModifiedTimeMap) { if (!oldFileToModifiedTimeMap[newFilePath] || oldFileToModifiedTimeMap[newFilePath] < newFileToModifiedTimeMap[newFilePath].getTime()) { bundleGeneratedAssetFiles.push(newFilePath); } } var manifest = []; if (bundleGeneratedAssetFiles.length) { bundleGeneratedAssetFiles.forEach(function(assetFile) { // Generate hash for each asset file var readStream = fs.createReadStream(resourcesDir + assetFile); var hashStream = crypto.createHash(HASH_ALGORITHM); readStream.pipe(hashStream) .on("error", function(error) { throw error; }) .on("finish", function() { hashStream.end(); var buffer = hashStream.read(); var fileHash = buffer.toString("hex"); manifest.push(CODE_PUSH_FOLDER_PREFIX + assetFile.replace(/\\/g, "/") + ":" + fileHash); if (manifest.length === bundleGeneratedAssetFiles.length) { // Generate hash for JS bundle readStream = fs.createReadStream(jsBundleFilePath); hashStream = crypto.createHash(HASH_ALGORITHM); readStream.pipe(hashStream) .on("error", function(error) { throw error; }) .on("finish", function() { hashStream.end(); var buffer = hashStream.read(); var fileHash = buffer.toString("hex"); manifest.push(CODE_PUSH_FOLDER_PREFIX + "/" + path.basename(jsBundleFilePath) + ":" + fileHash); manifest = manifest.sort(); var finalHash = crypto.createHash(HASH_ALGORITHM) .update(JSON.stringify(manifest)) .digest("hex"); var savedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_FILE_NAME; fs.writeFileSync(savedResourcesManifestPath, finalHash); }); } }); }); } fs.unlinkSync(TEMP_FILE_PATH);