electron-userland / electron-builder

A complete solution to package and build a ready for distribution Electron app with โ€œauto updateโ€ support out of the box
https://www.electron.build
MIT License
13.57k stars 1.73k forks source link

Can't start app from ZIP artifact #4299

Closed pashvin closed 3 years ago

pashvin commented 4 years ago
6.x

Extract app from ZIP and try to start it, fails with "The application xyz can't be opened".

wavifu commented 4 years ago

I created a small script to patch this on Mac Catalina.

https://gist.github.com/wavifu/7539e5bf84a715f6e728bd14479d477c

First, you need to let electron-builder build and release your app so that it generates latest-mac.yml. Then, run this script. This will re-pack the app using ditto, run app-builder command to retrieve hash and blockmap of the newly packed zip, and then modify the latest-mac.yml file. After that, you will just need to manually upload the .zip and the .yml file to your release server.

franzwarning commented 4 years ago

Would love to see a fix for this. Experiencing it as well

bcbee commented 4 years ago

This is breaking our app as well, would love to see a fix ๐Ÿ˜€

MehediH commented 4 years ago

@bcbee if you use @wavifu's patch, it works for now. Obviously not the best fix, but did the job for me now. It's better than having updates blocked :)

adam-lynch commented 4 years ago

Another workaround is to create a second ZIP. Edit out/targets/ArchiveTarget.js in node_modules. Duplicate the line where it creates the ZIP, so it'll create a second ZIP with a slightly different name.

+      await (0, _archive().archive)(format, artifactPath.replace('-mac.zip', '-mac-download.zip'), dirToArchive, archiveOptions);
       await (0, _archive().archive)(format, artifactPath, dirToArchive, archiveOptions);

Right after this, it appends the blockmap data to the auto-update ZIP. This won't be appended to the new (download) ZIP. Make sure this new download is uploaded to wherever you store downloads.

It's possible to name them ...-mac-update.zip (auto-update ZIP) and ...-mac.zip (download ZIP) if you play around with the electron-builder config too.

harshitsilly commented 4 years ago

Workaround for this is to use this gist after electron-builder generated output. https://gist.github.com/harshitsilly/a1bd5a405f93966aad20358ae6c4cec5 It will make the zip again with the use of ditto and generate the blockmap file and blocmap data and update in latest-mac.yml If using electron-updater, check mac-differential update - https://github.com/imjsElectron/electron-differential-updater

aabuhijleh commented 3 years ago

I'm using the dmg target for distributing my app. I'm only using the zip target because electron-updater needs it for updates to work.

After testing, this issue seems to be not affecting automatic updates. Is that accurate? Or did anyone find any issues here?

cenkalti commented 3 years ago

In my case, I instruct users to install the app from DMG. Zip does not work when installing the app but it is required for automated updates to work.

aabuhijleh commented 3 years ago

In my case, I instruct users to install the app from DMG. Zip does not work when installing the app but it is required for automated updates to work.

Yes, this is what I'm doing as well.

My question is:

Does this issue "The application xyz can't be opened" affect automatic updates?

For me, the answer seems to be: No

But I want to make sure

cenkalti commented 3 years ago

Does this issue "The application xyz can't be opened" affect automatic updates?

My answer is no as well.

mikekreeki commented 3 years ago

Confirming whats said above, installation from zip does not work but it's required for automatic updates for which it works ๐Ÿ‘

paragbaxi commented 3 years ago

Same issue: ./dist/mac/app execution dies immediately (no error message) ./dist/mac/app execution blocked with The application "app" cannot be opened. ./dist/app.dmg execution works

Ryuurock commented 3 years ago

Same issue: The application "app" cannot be opened.

stale[bot] commented 3 years ago

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

jthrilly commented 3 years ago

Yes this is still relevant. There are workarounds, but the issue needs a PR to resolve it in electron-builder.

jookyboi commented 3 years ago

Just tried it again on version 22.9.1 of electron-builder. Still the same problem.

harshitsilly commented 3 years ago

Try this gist https://gist.github.com/harshitsilly/a1bd5a405f93966aad20358ae6c4cec5

stale[bot] commented 3 years ago

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

hovancik commented 3 years ago

Yes.

mmaietta commented 3 years ago

Let me see if I can give this a shot. I see a few different options here:

  1. Generate 2 zips, one for electron-updater and another for direct downloads. (https://github.com/electron-userland/electron-builder/issues/4299#issuecomment-654106344)
  2. Disable embedding blockmap size for mac to avoid modifying the zip after compression (https://github.com/electron-userland/electron-builder/issues/4299#issuecomment-541249788)
  3. Replace 7zip to use ditto on mac?
  4. Change appendBlockmap to optionally allow an output file instead of writing on the zip itself. (https://github.com/develar/app-builder/issues/24#issue-524678610). This may be the best route? Not sure if/how this would affect electron-updater though.

When using any of these custom post-EB scripts (ditto <>.app -> rerun blockmap -> update latest-mac.yml), is that zip able to be used for both electron-updater and direct-download/install?

AFAICT, this seems more of a limitation imposed upon by MacOS, similar as to how we can use gatekeeperAssess: true in our EB config. So we could approach with another flag for disableEmbeddedBlockmap or something akin.

I took a look at the EB source and I can't identify what app-builder-bin blockmap {...} is doing that we can achieve all in one pass, as opposed to "appending" and modifying the zip signature. I don't use electron-updater, so I'm very unfamiliar with how the embedded blockmap is utilized specifically on mac.

Happy to put together a PR, just not sure on what route to go.

stale[bot] commented 3 years ago

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

vitor251093 commented 3 years ago

It is still relevant.

vitor251093 commented 3 years ago

Also, according to AWstats from cPanel, it seems that the automatic update system is downloading both the zip and the dmg for most of my users. I assume it's downloading the zip, noticing it was broken, and then downloading the dmg to solve the problem. I've recently made the dmg the default download (which is what I assume the path and sha512 of the YML root is), so I expect to put that theory to the test soon.

fmiceli24 commented 3 years ago

Still relevant!!!! I have to edit node_modules/app-builder-lib/out/targets/ArchiveTarget.js as explained below just to have a zip file that makes the updater work.

Update: Found the culprit: https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/src/targets/ArchiveTarget.ts#L65

After creating the zip, the default behavior for ArchiveTarget is to append the .blockmap to the file, then calculate the blockmapsize from that. This is in the name of doing differential updates.. though I've never seen electron-updater update this way for macOS.

I dug into node_modules/app-builder-lib/out/targets/ArchiveTarget.js and commented out this functionality:

if (this.isWriteUpdateInfo && format === "zip") {
  // updateInfo = await (0, _differentialUpdateInfoBuilder().appendBlockmap)(artifactPath);
}

The resulting latest-mac.yml will be missing the blockmapsize attribute but it doesn't seem to matter for me.

The resulting zip works fine on Catalina as does the auto-update functionality.

My theory is that by altering the zip file in this way (after compressing the notarized .app/ folder), we're confusing Catalina's Gatekeeper functionality.

mmaietta commented 3 years ago

@fmiceli24 you can use this with patch-package to have it persist for MacOS builds specifically. I'm not sure what the implications of the blockmap not being present will be for electron-updater. If it is indeed safe to disable blockmaps for mac zip target, then it's easy to turn this into a PR

app-builder-lib+22.11.5.patch

diff --git a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
index 77bdfb0..b788d5a 100644
--- a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
+++ b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js
@@ -59,7 +59,8 @@ class ArchiveTarget extends core_1.Target {
                 withoutDir,
             };
             await archive_1.archive(format, artifactPath, dirToArchive, archiveOptions);
-            if (this.isWriteUpdateInfo && format === "zip") {
+            // Disabled for mac zips: https://github.com/electron-userland/electron-builder/issues/4299
+            if (this.isWriteUpdateInfo && format === "zip" && !isMac) {
                 updateInfo = await differentialUpdateInfoBuilder_1.appendBlockmap(artifactPath);
             }
         }
vitor251093 commented 3 years ago

Thanks to @jookyboi 's 7za command, I've managed to replace the ZIP file with a functional one, but latest-mac-yml still had the info from the original ZIP file, so I had to create the JS file below, which receives the app version as an argument to work:

const fs = require('fs')
const yaml = require('yaml')
const child_process = require('child_process')

var args = process.argv.slice(2);
var version = args[0]

var filePath = './dist/latest-mac.yml'
var dataYaml = fs.readFileSync(filePath, {encoding: 'utf-8'})
var data = yaml.parse(dataYaml)

var zipFilePath = "./dist/My App-{version}-mac.zip".replace("{version}",version)
var regCommand = "shasum -a512 " + zipFilePath.replace(" ", "\\ ")
var output = child_process.execSync(regCommand, {encoding: 'utf-8'})
output = output.split(" ").shift().split("\t").shift()
output = new Buffer(output, 'hex').toString('base64') 
var stats = fs.statSync(zipFilePath)

var zipFile = data.files.filter(e => e.url.endsWith(".zip")).pop()
zipFile.sha512 = output
zipFile.size = stats.size

var dmgFile = data.files.filter(e => e.url.endsWith(".dmg")).pop()
data.path = dmgFile.url
data.sha512 = dmgFile.sha512

fs.writeFile(filePath, yaml.stringify(data), 'utf-8', function(){});

This is definitively just a workaround, and it requires yaml, but at least it is a workaround that worked for me, and that may work for someone else, so I decided to post it here.

fmiceli24 commented 3 years ago

diff --git a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js index 77bdfb0..b788d5a 100644 --- a/node_modules/app-builder-lib/out/targets/ArchiveTarget.js +++ b/node_modules/app-builder-lib/out/targets/ArchiveTarget.js @@ -59,7 +59,8 @@ class ArchiveTarget extends core_1.Target { withoutDir, }; await archive_1.archive(format, artifactPath, dirToArchive, archiveOptions);

Thanks. Did that in order to have it streamlined. I am not using the blockmap. I understand this is for delta updates, right?

If delta updates are not working on OSX, and enabling the blockmap breaks updates altogether, would it be possible to have this workaround implemented upstream in order to avoid patching?

sourabhverificient commented 3 years ago

My application is notarized so there is no issue with it, having said that I don't know zip artifact waits for notarization to be finish. I can try to compare content from zip app vs dmg app and see that has any difference

i am getting same issue even after notrization

sourabhverificient commented 3 years ago

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

"mac": { "target": ["tar.xz", "7z"] },

gniezen commented 3 years ago

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

Correct me if I'm wrong, but doesn't Squirrel.Mac require .zip artefacts? See (2) in Note here: https://www.electron.build/auto-update#quick-setup-guide

sourabhverificient commented 3 years ago

i ### solved this problem by using different target packaging in electron-builder "tar.xz"

Correct me if I'm wrong, but doesn't Squirrel.Mac require .zip artefacts? See (2) in Note here: https://www.electron.build/auto-update#quick-setup-guide

your right , in my use case i just wanted to compressed app which can launch after unzip i am not planning to autoupdate it at this moment.

RobertLowe commented 3 years ago

After a lot of pain I finally got this working, I spent more time figuring out codesign-ing and this issue than I did developing my app.

You can see my implementation here: https://github.com/RobertLowe/force-audio which is based on https://gist.github.com/harshitsilly/a1bd5a405f93966aad20358ae6c4cec5

I use a two step process:

  1. build the release as electron-builder wants,
  2. run the patcher AND reupload (and overwrite) to github releases.
mmaietta commented 3 years ago

I discovered that I can just swap it to generate an external .blockmap file so the zip isn't modified. Opened PR #6023

0xdeafcafe commented 3 years ago

@mmaietta Just used your changes in my local node_modules folder and this does work perfectly ๐ŸŽ‰, thank you so much! Do you know when the change will make it over to npm?

mmaietta commented 3 years ago

@0xdeafcafe I've just published next v22.11.9 to npm ๐Ÿ™‚ https://github.com/electron-userland/electron-builder/releases/tag/v22.11.9

Please note though...this issue was just reported but I've not been able to repro it in my 2 projects. So that's why I've published it as next https://github.com/electron-userland/electron-builder/issues/6045 If anyone could confirm if they experience the issue, please comment on that ticket and any additional debug data would be immensely helpful.

Vishal1419 commented 2 years ago

Writing this comment to help someone else facing the same issue in future.

I am using MacOS Mojave for development purposes I was using electron-builder v22.9.x and creating a zip file Then I was transferring generated .zip to my new laptop with MacOS Monterey via slack Then I was using Archive Utility to unzip the app. (If I use The Unarchiever it worked fine) I always got the error: Application cannot be opened

But when I saw above message from @mmaietta, I updated electron builder to v22.13.1 and then repeated the same process Now, I can see that blockmap file is generated correctly and my app on MacOS Monterey opens up correctly.

Thank you @mmaietta for resolving the issue.