Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions cropnlock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "pch.h"
#include "ChildWindow.h"

namespace util
{
using namespace robmikh::common::desktop;
using namespace robmikh::common::desktop::controls;
}

const std::wstring ChildWindow::ClassName = L"CropAndLock.ChildWindow";
std::once_flag ChildWindowClassRegistration;

void ChildWindow::RegisterWindowClass()
{
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));
WNDCLASSEXW wcex = {};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = instance;
wcex.hIcon = LoadIconW(instance, IDI_APPLICATION);
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcex.lpszClassName = ClassName.c_str();
wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION);
winrt::check_bool(RegisterClassExW(&wcex));
}

ChildWindow::ChildWindow(int width, int height, HWND parent)
{
auto instance = winrt::check_pointer(GetModuleHandleW(nullptr));

std::call_once(ChildWindowClassRegistration, []() { RegisterWindowClass(); });

auto exStyle = 0;
auto style = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

winrt::check_bool(CreateWindowExW(exStyle, ClassName.c_str(), L"", style,
0, 0, width, height, parent, nullptr, instance, this));
WINRT_ASSERT(m_window);

ShowWindow(m_window, SW_SHOW);
UpdateWindow(m_window);
}

LRESULT ChildWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam)
{
switch (message)
{
case WM_DESTROY:
break;
default:
return base_type::MessageHandler(message, wparam, lparam);
}
return 0;
}
125 changes: 125 additions & 0 deletions generateBundledResourcesHash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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";
var CODE_PUSH_HASH_OLD_FILE_NAME = "CodePushHash.json";
var HASH_ALGORITHM = "sha256";

var resourcesDir = process.argv[2];
var jsBundleFilePath = process.argv[3];
var assetsDir = process.argv[4];
var tempFileName = process.argv[5];

var oldFileToModifiedTimeMap = {};
var tempFileLocalPath = null;
if (tempFileName) {
tempFileLocalPath = path.join(require("os").tmpdir(), tempFileName);
oldFileToModifiedTimeMap = require(tempFileLocalPath);
}
var resourceFiles = [];

getFilesInFolder(resourcesDir, resourceFiles);

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
addFileToManifest(resourcesDir, assetFile, manifest, function() {
if (manifest.length === bundleGeneratedAssetFiles.length) {
addJsBundleAndMetaToManifest();
}
});
});
} else {
addJsBundleAndMetaToManifest();
}

function addJsBundleAndMetaToManifest() {
addFileToManifest(path.dirname(jsBundleFilePath), path.basename(jsBundleFilePath), manifest, function() {
var jsBundleMetaFilePath = jsBundleFilePath + ".meta";
addFileToManifest(path.dirname(jsBundleMetaFilePath), path.basename(jsBundleMetaFilePath), manifest, function() {
manifest = manifest.sort();
var finalHash = crypto.createHash(HASH_ALGORITHM)
.update(JSON.stringify(manifest))
.digest("hex");

console.log(finalHash);

var savedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_FILE_NAME;
fs.writeFileSync(savedResourcesManifestPath, finalHash);

// "CodePushHash.json" file name breaks flow type checking.
// To fix the issue we need to delete "CodePushHash.json" file and
// use "CodePushHash" file name instead to store the hash value.
// Relates to https://github.com/microsoft/react-native-code-push/issues/577
var oldSavedResourcesManifestPath = assetsDir + "/" + CODE_PUSH_HASH_OLD_FILE_NAME;
if (fs.existsSync(oldSavedResourcesManifestPath)) {
fs.unlinkSync(oldSavedResourcesManifestPath);
}
});
});
}

function addFileToManifest(folder, assetFile, manifest, done) {
var fullFilePath = path.join(folder, assetFile);
if (!fileExists(fullFilePath)) {
done();
return;
}

var readStream = fs.createReadStream(path.join(folder, 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(path.join(CODE_PUSH_FOLDER_PREFIX, assetFile).replace(/\\/g, "/") + ":" + fileHash);
done();
});
}

function fileExists(file) {
try { return fs.statSync(file).isFile(); }
catch (e) { return false; }
}

if (tempFileLocalPath) {
fs.unlinkSync(tempFileLocalPath);
}