Merge remote-tracking branch 'refs/remotes/atom/master'
This commit is contained in:
commit
c0ee8f4e60
36 changed files with 728 additions and 45 deletions
2
atom.gyp
2
atom.gyp
|
@ -4,7 +4,7 @@
|
|||
'product_name%': 'Electron',
|
||||
'company_name%': 'GitHub, Inc',
|
||||
'company_abbr%': 'github',
|
||||
'version%': '0.33.8',
|
||||
'version%': '0.34.0',
|
||||
},
|
||||
'includes': [
|
||||
'filenames.gypi',
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsBrowserProcess(base::CommandLine* cmd) {
|
||||
std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType);
|
||||
return process_type.empty();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AtomMainDelegate::AtomMainDelegate() {
|
||||
}
|
||||
|
||||
|
@ -28,11 +37,14 @@ AtomMainDelegate::~AtomMainDelegate() {
|
|||
}
|
||||
|
||||
bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
logging::LoggingSettings settings;
|
||||
#if defined(OS_WIN)
|
||||
// On Windows the terminal returns immediately, so we add a new line to
|
||||
// prevent output in the same line as the prompt.
|
||||
std::wcout << std::endl;
|
||||
if (IsBrowserProcess(command_line))
|
||||
std::wcout << std::endl;
|
||||
#if defined(DEBUG)
|
||||
// Print logging to debug.log on Windows
|
||||
settings.logging_dest = logging::LOG_TO_ALL;
|
||||
|
@ -47,7 +59,6 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||
#endif // !defined(OS_WIN)
|
||||
|
||||
// Only enable logging when --enable-logging is specified.
|
||||
auto command_line = base::CommandLine::ForCurrentProcess();
|
||||
if (!command_line->HasSwitch(switches::kEnableLogging)) {
|
||||
settings.logging_dest = logging::LOG_NONE;
|
||||
logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES);
|
||||
|
@ -83,7 +94,7 @@ void AtomMainDelegate::PreSandboxStartup() {
|
|||
}
|
||||
|
||||
// Only append arguments for browser process.
|
||||
if (!process_type.empty())
|
||||
if (!IsBrowserProcess(command_line))
|
||||
return;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "atom/browser/api/atom_api_download_item.h"
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "atom/browser/api/atom_api_web_contents.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/common/native_mate_converters/callback.h"
|
||||
#include "atom/common/native_mate_converters/gurl_converter.h"
|
||||
#include "atom/common/native_mate_converters/file_path_converter.h"
|
||||
|
@ -237,6 +238,8 @@ Session::~Session() {
|
|||
void Session::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
auto web_contents = item->GetWebContents();
|
||||
if (SavePageHandler::IsSavePageTypes(item->GetMimeType()))
|
||||
return;
|
||||
bool prevent_default = Emit(
|
||||
"will-download",
|
||||
DownloadItem::Create(isolate(), item),
|
||||
|
|
|
@ -162,6 +162,26 @@ struct Converter<net::HttpResponseHeaders*> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Converter<content::SavePageType> {
|
||||
static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
|
||||
content::SavePageType* out) {
|
||||
std::string save_type;
|
||||
if (!ConvertFromV8(isolate, val, &save_type))
|
||||
return false;
|
||||
if (save_type == "HTMLOnly") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML;
|
||||
} else if (save_type == "HTMLComplete") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML;
|
||||
} else if (save_type == "MHTML") {
|
||||
*out = content::SAVE_PAGE_TYPE_AS_MHTML;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mate
|
||||
|
||||
|
||||
|
@ -665,6 +685,13 @@ void WebContents::InsertCSS(const std::string& css) {
|
|||
web_contents()->InsertCSS(css);
|
||||
}
|
||||
|
||||
bool WebContents::SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback) {
|
||||
auto handler = new SavePageHandler(web_contents(), callback);
|
||||
return handler->Handle(full_file_path, save_type);
|
||||
}
|
||||
|
||||
void WebContents::ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture) {
|
||||
Send(new AtomViewMsg_ExecuteJavaScript(routing_id(), code, has_user_gesture));
|
||||
|
@ -976,6 +1003,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder(
|
|||
.SetMethod("setUserAgent", &WebContents::SetUserAgent)
|
||||
.SetMethod("getUserAgent", &WebContents::GetUserAgent)
|
||||
.SetMethod("insertCSS", &WebContents::InsertCSS)
|
||||
.SetMethod("savePage", &WebContents::SavePage)
|
||||
.SetMethod("_executeJavaScript", &WebContents::ExecuteJavaScript)
|
||||
.SetMethod("openDevTools", &WebContents::OpenDevTools)
|
||||
.SetMethod("closeDevTools", &WebContents::CloseDevTools)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "atom/browser/api/frame_subscriber.h"
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
#include "atom/browser/api/trackable_object.h"
|
||||
#include "atom/browser/common_web_contents_delegate.h"
|
||||
#include "content/public/browser/web_contents_observer.h"
|
||||
|
@ -73,6 +74,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void SetUserAgent(const std::string& user_agent);
|
||||
std::string GetUserAgent();
|
||||
void InsertCSS(const std::string& css);
|
||||
bool SavePage(const base::FilePath& full_file_path,
|
||||
const content::SavePageType& save_type,
|
||||
const SavePageHandler::SavePageCallback& callback);
|
||||
void ExecuteJavaScript(const base::string16& code,
|
||||
bool has_user_gesture);
|
||||
void OpenDevTools(mate::Arguments* args);
|
||||
|
|
78
atom/browser/api/save_page_handler.cc
Normal file
78
atom/browser/api/save_page_handler.cc
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/api/save_page_handler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "atom/browser/atom_browser_context.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
SavePageHandler::SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback)
|
||||
: web_contents_(web_contents),
|
||||
callback_(callback) {
|
||||
}
|
||||
|
||||
SavePageHandler::~SavePageHandler() {
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) {
|
||||
// OnDownloadCreated is invoked during WebContents::SavePage, so the |item|
|
||||
// here is the one stated by WebContents::SavePage.
|
||||
item->AddObserver(this);
|
||||
}
|
||||
|
||||
bool SavePageHandler::Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type) {
|
||||
auto download_manager = content::BrowserContext::GetDownloadManager(
|
||||
web_contents_->GetBrowserContext());
|
||||
download_manager->AddObserver(this);
|
||||
bool result = web_contents_->SavePage(full_path,
|
||||
full_path.DirName(),
|
||||
save_type);
|
||||
download_manager->RemoveObserver(this);
|
||||
// If initialization fails which means fail to create |DownloadItem|, we need
|
||||
// to delete the |SavePageHandler| instance to avoid memory-leak.
|
||||
if (!result)
|
||||
delete this;
|
||||
return result;
|
||||
}
|
||||
|
||||
void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) {
|
||||
if (item->IsDone()) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
if (item->GetState() == content::DownloadItem::COMPLETE) {
|
||||
callback_.Run(v8::Null(isolate));
|
||||
} else {
|
||||
v8::Local<v8::String> error_message = v8::String::NewFromUtf8(
|
||||
isolate, "Fail to save page");
|
||||
callback_.Run(v8::Exception::Error(error_message));
|
||||
}
|
||||
Destroy(item);
|
||||
}
|
||||
}
|
||||
|
||||
void SavePageHandler::Destroy(content::DownloadItem* item) {
|
||||
item->RemoveObserver(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
// static
|
||||
bool SavePageHandler::IsSavePageTypes(const std::string& type) {
|
||||
return type == "multipart/related" || type == "text/html";
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
60
atom/browser/api/save_page_handler.h
Normal file
60
atom/browser/api/save_page_handler.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2015 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "content/public/browser/download_item.h"
|
||||
#include "content/public/browser/download_manager.h"
|
||||
#include "content/public/browser/save_page_type.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace api {
|
||||
|
||||
// A self-destroyed class for handling save page request.
|
||||
class SavePageHandler : public content::DownloadManager::Observer,
|
||||
public content::DownloadItem::Observer {
|
||||
public:
|
||||
using SavePageCallback = base::Callback<void(v8::Local<v8::Value>)>;
|
||||
|
||||
SavePageHandler(content::WebContents* web_contents,
|
||||
const SavePageCallback& callback);
|
||||
~SavePageHandler();
|
||||
|
||||
bool Handle(const base::FilePath& full_path,
|
||||
const content::SavePageType& save_type);
|
||||
|
||||
static bool IsSavePageTypes(const std::string& type);
|
||||
|
||||
private:
|
||||
void Destroy(content::DownloadItem* item);
|
||||
|
||||
// content::DownloadManager::Observer:
|
||||
void OnDownloadCreated(content::DownloadManager* manager,
|
||||
content::DownloadItem* item) override;
|
||||
|
||||
// content::DownloadItem::Observer:
|
||||
void OnDownloadUpdated(content::DownloadItem* item) override;
|
||||
|
||||
content::WebContents* web_contents_; // weak
|
||||
SavePageCallback callback_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_
|
|
@ -18,6 +18,25 @@ require path.resolve(__dirname, '..', '..', 'common', 'lib', 'init')
|
|||
globalPaths = Module.globalPaths
|
||||
globalPaths.push path.resolve(__dirname, '..', 'api', 'lib')
|
||||
|
||||
if process.platform is 'win32'
|
||||
# Redirect node's console to use our own implementations, since node can not
|
||||
# handle console output when running as GUI program.
|
||||
consoleLog = (args...) ->
|
||||
process.log util.format(args...) + "\n"
|
||||
streamWrite = (chunk, encoding, callback) ->
|
||||
chunk = chunk.toString(encoding) if Buffer.isBuffer chunk
|
||||
process.log chunk
|
||||
callback() if callback
|
||||
true
|
||||
console.log = console.error = console.warn = consoleLog
|
||||
process.stdout.write = process.stderr.write = streamWrite
|
||||
|
||||
# Always returns EOF for stdin stream.
|
||||
Readable = require('stream').Readable
|
||||
stdin = new Readable
|
||||
stdin.push null
|
||||
process.__defineGetter__ 'stdin', -> stdin
|
||||
|
||||
# Don't quit on fatal error.
|
||||
process.on 'uncaughtException', (error) ->
|
||||
# Do nothing if the user has a custom uncaught exception handler.
|
||||
|
|
|
@ -69,7 +69,9 @@ unwrapArgs = (sender, args) ->
|
|||
rendererReleased = true
|
||||
|
||||
ret = ->
|
||||
throw new Error('Calling a callback of released renderer view') if rendererReleased
|
||||
if rendererReleased
|
||||
throw new Error("Attempting to call a function in a renderer window
|
||||
that has been closed or released. Function provided here: #{meta.id}.")
|
||||
sender.send 'ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, arguments)
|
||||
v8Util.setDestructor ret, ->
|
||||
return if rendererReleased
|
||||
|
|
|
@ -116,7 +116,8 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
|
|||
} else if (options.Get(switches::kCenter, ¢er) && center) {
|
||||
Center();
|
||||
}
|
||||
extensions::SizeConstraints size_constraints;
|
||||
// On Linux and Window we may already have maximum size defined.
|
||||
extensions::SizeConstraints size_constraints(GetContentSizeConstraints());
|
||||
int min_height = 0, min_width = 0;
|
||||
if (options.Get(switches::kMinHeight, &min_height) |
|
||||
options.Get(switches::kMinWidth, &min_width)) {
|
||||
|
|
|
@ -390,7 +390,10 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
|||
void NativeWindowViews::SetContentSizeConstraints(
|
||||
const extensions::SizeConstraints& size_constraints) {
|
||||
NativeWindow::SetContentSizeConstraints(size_constraints);
|
||||
window_->OnSizeConstraintsChanged();
|
||||
// widget_delegate() is only available after Init() is called, we make use of
|
||||
// this to determine whether native widget has initialized.
|
||||
if (window_ && window_->widget_delegate())
|
||||
window_->OnSizeConstraintsChanged();
|
||||
#if defined(USE_X11)
|
||||
if (resizable_)
|
||||
old_size_constraints_ = size_constraints;
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundleIconFile</key>
|
||||
<string>atom.icns</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.33.8</string>
|
||||
<string>0.34.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.33.8</string>
|
||||
<string>0.34.0</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.developer-tools</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -56,8 +56,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,33,8,0
|
||||
PRODUCTVERSION 0,33,8,0
|
||||
FILEVERSION 0,34,0,0
|
||||
PRODUCTVERSION 0,34,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -74,12 +74,12 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "GitHub, Inc."
|
||||
VALUE "FileDescription", "Electron"
|
||||
VALUE "FileVersion", "0.33.8"
|
||||
VALUE "FileVersion", "0.34.0"
|
||||
VALUE "InternalName", "electron.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
|
||||
VALUE "OriginalFilename", "electron.exe"
|
||||
VALUE "ProductName", "Electron"
|
||||
VALUE "ProductVersion", "0.33.8"
|
||||
VALUE "ProductVersion", "0.34.0"
|
||||
VALUE "SquirrelAwareVersion", "1"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace {
|
|||
const char* kWebRuntimeFeatures[] = {
|
||||
switches::kExperimentalFeatures,
|
||||
switches::kExperimentalCanvasFeatures,
|
||||
switches::kSubpixelFontScaling,
|
||||
switches::kOverlayScrollbars,
|
||||
switches::kOverlayFullscreenVideo,
|
||||
switches::kSharedWorker,
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
savedGlobal = global # the "global.global" might be deleted later
|
||||
|
||||
module.exports =
|
||||
class CallbacksRegistry
|
||||
constructor: ->
|
||||
@emptyFunc = -> throw new Error "Browser trying to call a non-exist callback
|
||||
in renderer, this usually happens when renderer code forgot to release
|
||||
a callback installed on objects in browser when renderer was going to be
|
||||
unloaded or released."
|
||||
@nextId = 0
|
||||
@callbacks = {}
|
||||
|
||||
add: (callback) ->
|
||||
id = Math.random().toString()
|
||||
id = ++@nextId
|
||||
|
||||
# Capture the location of the function and put it in the ID string,
|
||||
# so that release errors can be tracked down easily.
|
||||
regexp = /at (.*)/gi
|
||||
stackString = (new Error).stack
|
||||
|
||||
while (match = regexp.exec(stackString)) isnt null
|
||||
[x, location] = match
|
||||
continue if location.indexOf('(native)') isnt -1
|
||||
continue if location.indexOf('atom.asar') isnt -1
|
||||
[x, filenameAndLine] = /([^/^\)]*)\)?$/gi.exec(location)
|
||||
id = "#{filenameAndLine} (#{id})"
|
||||
break
|
||||
|
||||
@callbacks[id] = callback
|
||||
id
|
||||
|
||||
|
@ -18,10 +27,10 @@ class CallbacksRegistry
|
|||
@callbacks[id] ? ->
|
||||
|
||||
call: (id, args...) ->
|
||||
@get(id).call savedGlobal, args...
|
||||
@get(id).call global, args...
|
||||
|
||||
apply: (id, args...) ->
|
||||
@get(id).apply savedGlobal, args...
|
||||
@get(id).apply global, args...
|
||||
|
||||
remove: (id) ->
|
||||
delete @callbacks[id]
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#define ATOM_VERSION_H
|
||||
|
||||
#define ATOM_MAJOR_VERSION 0
|
||||
#define ATOM_MINOR_VERSION 33
|
||||
#define ATOM_PATCH_VERSION 8
|
||||
#define ATOM_MINOR_VERSION 34
|
||||
#define ATOM_PATCH_VERSION 0
|
||||
|
||||
#define ATOM_VERSION_IS_RELEASE 1
|
||||
|
||||
|
|
|
@ -11,6 +11,25 @@
|
|||
#include "base/memory/singleton.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "gin/public/debug.h"
|
||||
#include "sandbox/win/src/nt_internals.h"
|
||||
|
||||
#pragma intrinsic(_AddressOfReturnAddress)
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
|
||||
#ifdef _WIN64
|
||||
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
|
||||
typedef struct _UNWIND_INFO {
|
||||
unsigned char Version : 3;
|
||||
unsigned char Flags : 5;
|
||||
unsigned char SizeOfProlog;
|
||||
unsigned char CountOfCodes;
|
||||
unsigned char FrameRegister : 4;
|
||||
unsigned char FrameOffset : 4;
|
||||
ULONG ExceptionHandler;
|
||||
} UNWIND_INFO, *PUNWIND_INFO;
|
||||
#endif
|
||||
|
||||
namespace crash_reporter {
|
||||
|
||||
|
@ -24,6 +43,94 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
|
|||
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
|
||||
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
|
||||
|
||||
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
|
||||
NTSTATUS ExitStatus);
|
||||
char* g_real_terminate_process_stub = NULL;
|
||||
|
||||
void TerminateProcessWithoutDump() {
|
||||
// Patched stub exists based on conditions (See InitCrashReporter).
|
||||
// As a side note this function also gets called from
|
||||
// WindowProcExceptionFilter.
|
||||
if (g_real_terminate_process_stub == NULL) {
|
||||
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
|
||||
} else {
|
||||
NtTerminateProcessPtr real_terminate_proc =
|
||||
reinterpret_cast<NtTerminateProcessPtr>(
|
||||
static_cast<char*>(g_real_terminate_process_stub));
|
||||
real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
int CrashForExceptionInNonABICompliantCodeRange(
|
||||
PEXCEPTION_RECORD ExceptionRecord,
|
||||
ULONG64 EstablisherFrame,
|
||||
PCONTEXT ContextRecord,
|
||||
PDISPATCHER_CONTEXT DispatcherContext) {
|
||||
EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
|
||||
if (!CrashReporter::GetInstance())
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
|
||||
CrashForException(&info);
|
||||
}
|
||||
|
||||
struct ExceptionHandlerRecord {
|
||||
RUNTIME_FUNCTION runtime_function;
|
||||
UNWIND_INFO unwind_info;
|
||||
unsigned char thunk[12];
|
||||
};
|
||||
|
||||
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
// We assume that the first page of the code range is executable and
|
||||
// committed and reserved for breakpad. What could possibly go wrong?
|
||||
|
||||
// All addresses are 32bit relative offsets to start.
|
||||
record->runtime_function.BeginAddress = 0;
|
||||
record->runtime_function.EndAddress =
|
||||
base::checked_cast<DWORD>(size_in_bytes);
|
||||
record->runtime_function.UnwindData =
|
||||
offsetof(ExceptionHandlerRecord, unwind_info);
|
||||
|
||||
// Create unwind info that only specifies an exception handler.
|
||||
record->unwind_info.Version = 1;
|
||||
record->unwind_info.Flags = UNW_FLAG_EHANDLER;
|
||||
record->unwind_info.SizeOfProlog = 0;
|
||||
record->unwind_info.CountOfCodes = 0;
|
||||
record->unwind_info.FrameRegister = 0;
|
||||
record->unwind_info.FrameOffset = 0;
|
||||
record->unwind_info.ExceptionHandler =
|
||||
offsetof(ExceptionHandlerRecord, thunk);
|
||||
|
||||
// Hardcoded thunk.
|
||||
// mov imm64, rax
|
||||
record->thunk[0] = 0x48;
|
||||
record->thunk[1] = 0xb8;
|
||||
void* handler = &CrashForExceptionInNonABICompliantCodeRange;
|
||||
memcpy(&record->thunk[2], &handler, 8);
|
||||
|
||||
// jmp rax
|
||||
record->thunk[10] = 0xff;
|
||||
record->thunk[11] = 0xe0;
|
||||
|
||||
// Protect reserved page against modifications.
|
||||
DWORD old_protect;
|
||||
CHECK(VirtualProtect(
|
||||
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
|
||||
CHECK(RtlAddFunctionTable(
|
||||
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
|
||||
}
|
||||
|
||||
void UnregisterNonABICompliantCodeRange(void* start) {
|
||||
ExceptionHandlerRecord* record =
|
||||
reinterpret_cast<ExceptionHandlerRecord*>(start);
|
||||
|
||||
CHECK(RtlDeleteFunctionTable(&record->runtime_function));
|
||||
}
|
||||
#endif // _WIN64
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashReporterWin::CrashReporterWin() {
|
||||
|
@ -63,26 +170,46 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
|
|||
// to allow any previous handler to detach in the correct order.
|
||||
breakpad_.reset();
|
||||
|
||||
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
|
||||
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
|
||||
breakpad_.reset(new google_breakpad::ExceptionHandler(
|
||||
temp_dir.value(),
|
||||
FilterCallback,
|
||||
MinidumpCallback,
|
||||
this,
|
||||
handler_types,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
kSmallDumpType,
|
||||
pipe_name.c_str(),
|
||||
GetCustomInfo(product_name, version, company_name)));
|
||||
|
||||
if (!breakpad_->IsOutOfProcess())
|
||||
LOG(ERROR) << "Cannot initialize out-of-process crash handler";
|
||||
|
||||
#ifdef _WIN64
|
||||
// Hook up V8 to breakpad.
|
||||
{
|
||||
// gin::Debug::SetCodeRangeCreatedCallback only runs the callback when
|
||||
// Isolate is just created, so we have to manually run following code here.
|
||||
void* code_range = nullptr;
|
||||
size_t size = 0;
|
||||
v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size);
|
||||
if (code_range && size)
|
||||
RegisterNonABICompliantCodeRange(code_range, size);
|
||||
}
|
||||
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CrashReporterWin::SetUploadParameters() {
|
||||
upload_parameters_["platform"] = "win32";
|
||||
}
|
||||
|
||||
int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
|
||||
if (breakpad_) {
|
||||
breakpad_->WriteMinidumpForException(info);
|
||||
TerminateProcessWithoutDump();
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CrashReporterWin::FilterCallback(void* context,
|
||||
EXCEPTION_POINTERS* exinfo,
|
||||
|
|
|
@ -29,6 +29,9 @@ class CrashReporterWin : public CrashReporter {
|
|||
bool skip_system_crash_handler) override;
|
||||
void SetUploadParameters() override;
|
||||
|
||||
// Crashes the process after generating a dump for the provided exception.
|
||||
int CrashForException(EXCEPTION_POINTERS* info);
|
||||
|
||||
private:
|
||||
friend struct DefaultSingletonTraits<CrashReporterWin>;
|
||||
|
||||
|
|
|
@ -311,7 +311,7 @@ bool CrashService::Initialize(const base::string16& application_name,
|
|||
// service is initialized.
|
||||
base::string16 wait_name = ReplaceStringPlaceholders(
|
||||
kWaitEventFormat, application_name, NULL);
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str());
|
||||
HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str());
|
||||
::SetEvent(wait_event);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -99,7 +99,6 @@ const char kClientCertificate[] = "client-certificate";
|
|||
// Web runtime features.
|
||||
const char kExperimentalFeatures[] = "experimental-features";
|
||||
const char kExperimentalCanvasFeatures[] = "experimental-canvas-features";
|
||||
const char kSubpixelFontScaling[] = "subpixel-font-scaling";
|
||||
const char kOverlayScrollbars[] = "overlay-scrollbars";
|
||||
const char kOverlayFullscreenVideo[] = "overlay-fullscreen-video";
|
||||
const char kSharedWorker[] = "shared-worker";
|
||||
|
|
|
@ -51,7 +51,6 @@ extern const char kClientCertificate[];
|
|||
|
||||
extern const char kExperimentalFeatures[];
|
||||
extern const char kExperimentalCanvasFeatures[];
|
||||
extern const char kSubpixelFontScaling[];
|
||||
extern const char kOverlayScrollbars[];
|
||||
extern const char kOverlayFullscreenVideo[];
|
||||
extern const char kSharedWorker[];
|
||||
|
|
|
@ -234,8 +234,6 @@ void AtomRendererClient::EnableWebRuntimeFeatures() {
|
|||
blink::WebRuntimeFeatures::enableExperimentalFeatures(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kExperimentalCanvasFeatures, &b))
|
||||
blink::WebRuntimeFeatures::enableExperimentalCanvasFeatures(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kSubpixelFontScaling, &b))
|
||||
blink::WebRuntimeFeatures::enableSubpixelFontScaling(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kOverlayScrollbars, &b))
|
||||
blink::WebRuntimeFeatures::enableOverlayScrollbars(b);
|
||||
if (IsSwitchEnabled(command_line, switches::kOverlayFullscreenVideo, &b))
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
## Guias
|
||||
|
||||
* [Distribuir Aplicação](tutorial/application-distribution.md)
|
||||
* [Distribuição de Aplicações](tutorial/application-distribution.md)
|
||||
* [Empacotamento da aplicação](tutorial/application-packaging.md)
|
||||
* [Usando módulos nativos](../../docs/tutorial/using-native-node-modules.md)
|
||||
* [Depuração do processo principal](../../docs/tutorial/debugging-main-process.md)
|
||||
* [Usando módulos nativos](tutorial/using-native-node-modules.md)
|
||||
* [Depuração do processo principal](tutorial/debugging-main-process.md)
|
||||
* [Usando Selenium e WebDriver](../../docs/tutorial/using-selenium-and-webdriver.md)
|
||||
* [Extensão DevTools](../../docs/tutorial/devtools-extension.md)
|
||||
* [Usando o plugin papper flash](../../docs/tutorial/using-pepper-flash-plugin.md)
|
||||
* [Usando o plugin papper flash](tutorial/using-pepper-flash-plugin.md)
|
||||
|
||||
## Tutoriais
|
||||
|
||||
|
|
53
docs-translations/pt-BR/tutorial/debugging-main-process.md
Normal file
53
docs-translations/pt-BR/tutorial/debugging-main-process.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Depurando o Processo Principal
|
||||
|
||||
A janela do navegador, DevTools, pode somente depurar o processo de renderização
|
||||
de scripts (por exemplo, as páginas da web). Para providenciar um modo de
|
||||
depurar os scripts através do processo principal, o Electron criou as opções
|
||||
`--debug` e `--debug-brk`.
|
||||
|
||||
## Opções da Linha de Comando
|
||||
|
||||
Use a seguinte opção na linha de comando para depurar o processo principal do
|
||||
Electron:
|
||||
|
||||
### `--debug=[porta]`
|
||||
|
||||
Quando este comando é usado, o Electron irá executar o protocolo de depuração
|
||||
V8 mandando as mensagens na `porta`. A `porta` padrão é `5858`.
|
||||
|
||||
### `--debug-brk=[porta]`
|
||||
|
||||
Semelhante ao `--debug`, porém pausa o script na primeira linha.
|
||||
|
||||
## Usando node-inspector para depurar
|
||||
|
||||
__Nota:__ O Electron usa a versão v0.11.13 do Node, a qual, atualmenta não
|
||||
funciona muito bem com node-inspector, e o processo principal irá quebrar se
|
||||
você inspecionar o objeto `process` pelo console do node-inspector.
|
||||
|
||||
### 1. Inicie o servidor [node-inspector][node-inspector]
|
||||
|
||||
```bash
|
||||
$ node-inspector
|
||||
```
|
||||
|
||||
### 2. Habilite o modo de depuração para o Electron
|
||||
|
||||
Você pode também iniciar o Electron com um ponto de depuração, desta maneira:
|
||||
|
||||
```bash
|
||||
$ electron --debug=5858 sua/aplicacao
|
||||
```
|
||||
|
||||
ou para pausar o script na primeira linha:
|
||||
|
||||
```bash
|
||||
$ electron --debug-brk=5858 sua/aplicacao
|
||||
```
|
||||
|
||||
### 3. Carregue o debugger UI
|
||||
|
||||
Abra este endereço http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858
|
||||
usando o Chrome.
|
||||
|
||||
[node-inspector]: https://github.com/node-inspector/node-inspector
|
|
@ -0,0 +1,68 @@
|
|||
# Usando Módulos Nativos do Node
|
||||
|
||||
Os módulos nativos do Node são suportados pelo Electron, desde que o Electron
|
||||
esteja usando uma versão diferente da oficial V8 do Node, você tem de
|
||||
especificar manualmente a localização das headers do Electron quando compilar os
|
||||
módulos nativos.
|
||||
|
||||
## Compatibilidade de Módulos Nativos do Node
|
||||
|
||||
Módulos nativos podem quebrar quando utilizar a nova versão do Node, V8.
|
||||
Para ter certeza que o módulo que você está interessado em trabalhar com o
|
||||
Electron, você deve checar se a versão do Node utilizada é compatível com a
|
||||
usada pelo Electron.
|
||||
Você pode verificar qual versão do Node foi utilizada no Electron olhando na
|
||||
página [releases](https://github.com/atom/electron/releases) ou usando
|
||||
`process.version` (veja [Quick Start](https://github.com/atom/electron/blob/master/docs/tutorial/quick-start.md)
|
||||
por exemplo).
|
||||
|
||||
Considere usar [NAN](https://github.com/nodejs/nan/) para seus próprios
|
||||
módulos, caso isso facilite o suporte da múltiplas versões do Node. Isso é
|
||||
também de grande ajuda para fazer a portabilidade dos módulos antigos para as
|
||||
versões mais novas do Node, assim podendo trabalhar com o Electron.
|
||||
|
||||
## Como Instalar os Módulos Nativos
|
||||
|
||||
Existem três maneiras de instalar os módulos nativos:
|
||||
|
||||
### O Modo Fácil
|
||||
|
||||
O modo mais direto para recompilar os módulos é pelo pacote
|
||||
[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild),
|
||||
o que lida com passos manuais para baixar as headers e construir os módulos
|
||||
nativos:
|
||||
|
||||
```sh
|
||||
npm install --save-dev electron-rebuild
|
||||
|
||||
# Sempre que rodar npm install, execute também:
|
||||
node ./node_modules/.bin/electron-rebuild
|
||||
```
|
||||
|
||||
### Via npm
|
||||
|
||||
Você pode usar também `npm` para instalar os módulos. Os passos são exatamente
|
||||
os mesmos com os módulos Node, exceto que você precisa configurar algumas
|
||||
variáveis da ambiente:
|
||||
|
||||
```bash
|
||||
export npm_config_disturl=https://atom.io/download/atom-shell
|
||||
export npm_config_target=0.33.1
|
||||
export npm_config_arch=x64
|
||||
export npm_config_runtime=electron
|
||||
HOME=~/.electron-gyp npm install module-name
|
||||
```
|
||||
|
||||
### O modo node-gyp
|
||||
|
||||
Para compilar os módulos do Node com as headers do Electron, você precisa dizer
|
||||
ao `node-gyp` onde baixar as headers e qual versão usar:
|
||||
|
||||
```bash
|
||||
$ cd /path-to-module/
|
||||
$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell
|
||||
```
|
||||
|
||||
A tag `HOME=~/.electron-gyp` altera onde encontrar as headers de desenvolvimento.
|
||||
A tag `--target=0.29.1` é a versão do Electron. A tag `--dist-url=...` especifica
|
||||
onde baixar as headers. A tag `--arch=x64` diz ao módulo que é feito em 64bit.
|
|
@ -0,0 +1,68 @@
|
|||
# Usando o Plugin Pepper Flash
|
||||
|
||||
Electron atualmente suporta o plugin Pepper Flash. Para usá-lo no Electron,
|
||||
você deve especificar manualmente a localização do plugin e então ele será
|
||||
habilitado em sua aplicação.
|
||||
|
||||
## Prepare uma cópia do plugin Flash
|
||||
|
||||
Tanto no OS X como no Linux, os detalhes do plugin Pepper Flash podem ser
|
||||
encontrados navegando por `chrome://plugins` no navegador Chrome. Essa
|
||||
localização e versão são úteis para o suporte do plugin Electron's Pepper Flash.
|
||||
Você pode também copiar para outra localização.
|
||||
|
||||
## Adicionando a opçao Electron
|
||||
|
||||
Você pode adicionar diretamente `--ppapi-flash-path` e `ppapi-flash-version`
|
||||
para a linha de comando do Electron ou usando o método
|
||||
`app.commandLine.appendSwitch` após o evento pronto. Também, adicione a opção
|
||||
`plugins` em `browser-window`.
|
||||
Por exemplo:
|
||||
|
||||
```javascript
|
||||
var app = require('app');
|
||||
var BrowserWindow = require('browser-window');
|
||||
|
||||
// Informa os erros ao ao servidor.
|
||||
require('crash-reporter').start();
|
||||
|
||||
// Mantém uma referência global da janela, se não manter, a janela irá fechar
|
||||
// automaticamente quando o objeto javascript for GCed.
|
||||
var mainWindow = null;
|
||||
|
||||
// Sai assim que todas as janelas forem fechadas.
|
||||
app.on('window-all-closed', function() {
|
||||
if (process.platform != 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
// Epecifica o caminho do flash.
|
||||
// No Windows, deve ser /path/to/pepflashplayer.dll
|
||||
// No Mac, /path/to/PepperFlashPlayer.plugin
|
||||
// No Linux, /path/to/libpepflashplayer.so
|
||||
app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so');
|
||||
|
||||
// Especifica a versão do flash, por exemplo, v17.0.0.169
|
||||
app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169');
|
||||
|
||||
app.on('ready', function() {
|
||||
mainWindow = new BrowserWindow({
|
||||
'width': 800,
|
||||
'height': 600,
|
||||
'web-preferences': {
|
||||
'plugins': true
|
||||
}
|
||||
});
|
||||
mainWindow.loadUrl('file://' + __dirname + '/index.html');
|
||||
// Algo mais
|
||||
});
|
||||
```
|
||||
|
||||
## Ative o plugin Flash na tag `<webview>`
|
||||
|
||||
Adicione o atributo `plugins` na tag `<webview>`.
|
||||
|
||||
```html
|
||||
<webview src="http://www.adobe.com/software/flash/about/" plugins></webview>
|
||||
```
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
* [Supported Platforms](tutorial/supported-platforms.md)
|
||||
* [Application Distribution](tutorial/application-distribution.md)
|
||||
* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md)
|
||||
* [Application Packaging](tutorial/application-packaging.md)
|
||||
* [Using Native Node Modules](tutorial/using-native-node-modules.md)
|
||||
* [Debugging Main Process](tutorial/debugging-main-process.md)
|
||||
|
|
|
@ -111,7 +111,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||
* `plugins` Boolean - Whether plugins should be enabled.
|
||||
* `experimental-features` Boolean
|
||||
* `experimental-canvas-features` Boolean
|
||||
* `subpixel-font-scaling` Boolean
|
||||
* `overlay-scrollbars` Boolean
|
||||
* `overlay-fullscreen-video` Boolean
|
||||
* `shared-worker` Boolean
|
||||
|
|
|
@ -8,6 +8,8 @@ upstream node:
|
|||
* `process.versions['electron']` String - Version of Electron.
|
||||
* `process.versions['chrome']` String - Version of Chromium.
|
||||
* `process.resourcesPath` String - Path to JavaScript source code.
|
||||
* `process.mas` Boolean - For Mac App Store build, this value is `true`, for
|
||||
other builds it is `undefined`.
|
||||
|
||||
## Events
|
||||
|
||||
|
@ -37,7 +39,7 @@ The `process` object has the following method:
|
|||
|
||||
Causes the main thread of the current process hang.
|
||||
|
||||
### process.setFdLimit(maxDescriptors) _OS X_ _Linux_
|
||||
### `process.setFdLimit(maxDescriptors)` _OS X_ _Linux_
|
||||
|
||||
* `maxDescriptors` Integer
|
||||
|
||||
|
|
|
@ -631,3 +631,26 @@ Get the `WebContents` of DevTools for this `WebContents`.
|
|||
|
||||
**Note:** Users should never store this object because it may become `null`
|
||||
when the DevTools has been closed.
|
||||
|
||||
### `webContents.savePage(fullPath, saveType, callback)`
|
||||
|
||||
* `fullPath` String - The full file path.
|
||||
* `saveType` String - Specify the save type.
|
||||
* `HTMLOnly` - Save only the HTML of the page.
|
||||
* `HTMLComplete` - Save complete-html page.
|
||||
* `MHTML` - Save complete-html page as MHTML.
|
||||
* `callback` Function - `function(error) {}`.
|
||||
* `error` Error
|
||||
|
||||
Returns true if the process of saving page has been initiated successfully.
|
||||
|
||||
```javascript
|
||||
win.loadUrl('https://github.com');
|
||||
|
||||
win.webContents.on('did-finish-load', function() {
|
||||
win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function(error) {
|
||||
if (!error)
|
||||
console.log("Save page successfully");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
|
115
docs/tutorial/mac-app-store-submission-guide.md
Normal file
115
docs/tutorial/mac-app-store-submission-guide.md
Normal file
|
@ -0,0 +1,115 @@
|
|||
# Mac App Store Submission Guide
|
||||
|
||||
Since v0.34.0, Electron allows submitting packaged apps to Mac App Store (MAS),
|
||||
this guide provides information on how to submit your app, and the limitations
|
||||
of the MAS build.
|
||||
|
||||
## How to submit your app
|
||||
|
||||
Following steps introduces a simple way to submit your app to Mac App Store, but
|
||||
it doesn't make sure your app gets approved by Apple, you still have to read
|
||||
apple's [Submitting Your App][submitting-your-app] guide on how to meet Mac
|
||||
App Store's requirements.
|
||||
|
||||
### Get certificate
|
||||
|
||||
To submit your app to Mac App Store, you have to get a certificate from Apple
|
||||
first, you can follow [existing guides][nwjs-guide] on web.
|
||||
|
||||
### Sign your app
|
||||
|
||||
After getting the certificate, you can package your app by following
|
||||
[Application Distribution](application-distribution.md), and then sign your app.
|
||||
The step is basically the same with other programs, the key is to sign every
|
||||
dependency of Electron one by one.
|
||||
|
||||
First you need to prepare two entitlements files.
|
||||
|
||||
`child.plist`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.inherit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
`parent.plist`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
And then sign your app with following script:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Name of your app.
|
||||
APP="YourApp"
|
||||
# The path of you app to sign.
|
||||
APP_PATH="/path/to/YouApp.app"
|
||||
# The path to the location you want to put the signed package.
|
||||
RESULT_PATH="~/Desktop/$APP.pkg"
|
||||
# The name of certificates you requested.
|
||||
APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)"
|
||||
INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)"
|
||||
|
||||
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
|
||||
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib"
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework"
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/"
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/"
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/"
|
||||
codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/"
|
||||
codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH"
|
||||
productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$APP_PATH"
|
||||
```
|
||||
|
||||
If you are new to app sandboxing of OS X, you should also go through Apple's
|
||||
[Enabling App Sandbox][enable-app-sandbox] to have a basic idea, and add keys
|
||||
for the permissions needed by your app to the entitlements files.
|
||||
|
||||
### Upload your app and submit for review
|
||||
|
||||
After signing your app you can use Application Loader to upload it to iTunes
|
||||
Connect for processing, make sure you have [created a record][create-record]
|
||||
before uploading. Then you can [submit your app for review][submit-for-review].
|
||||
|
||||
## Limitations of MAS build
|
||||
|
||||
In order to satisfy requirements for app sandboxing, following modules have been
|
||||
disabled in MAS build:
|
||||
|
||||
* `crash-reporter`
|
||||
* `auto-updater`
|
||||
|
||||
and following behaviors have been changed:
|
||||
|
||||
* Video capture may not work for some machines.
|
||||
* Certain accessibility features may not work.
|
||||
* Apps will not be aware of DNS changes.
|
||||
|
||||
Also due to the usage of app sandboxing, the resources can be accessed by the
|
||||
app is strictly limited, you can read [App Sandboxing][app-sandboxing] for more.
|
||||
|
||||
[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html
|
||||
[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps
|
||||
[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html
|
||||
[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html
|
||||
[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html
|
||||
[app-sandboxing]: https://developer.apple.com/app-sandboxing/
|
|
@ -108,6 +108,8 @@
|
|||
'atom/browser/api/trackable_object.h',
|
||||
'atom/browser/api/frame_subscriber.cc',
|
||||
'atom/browser/api/frame_subscriber.h',
|
||||
'atom/browser/api/save_page_handler.cc',
|
||||
'atom/browser/api/save_page_handler.h',
|
||||
'atom/browser/auto_updater.cc',
|
||||
'atom/browser/auto_updater.h',
|
||||
'atom/browser/auto_updater_delegate.h',
|
||||
|
|
|
@ -7,8 +7,8 @@ import sys
|
|||
|
||||
|
||||
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
|
||||
'http://github-janky-artifacts.s3.amazonaws.com/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '04523758cda2a96d2454f9056fb1fb9a1c1f95f1'
|
||||
'http://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent'
|
||||
LIBCHROMIUMCONTENT_COMMIT = '78e54bc39a04b758ed5167cd980cc4d9951bd629'
|
||||
|
||||
PLATFORM = {
|
||||
'cygwin': 'win32',
|
||||
|
|
|
@ -301,3 +301,15 @@ describe 'browser-window module', ->
|
|||
assert.notEqual data.length, 0
|
||||
w.webContents.endFrameSubscription()
|
||||
done()
|
||||
|
||||
describe 'save page', ->
|
||||
savePagePath = path.join fixtures, 'save_page.html'
|
||||
it 'should save page', (done) ->
|
||||
w.webContents.on 'did-finish-load', ->
|
||||
w.webContents.savePage savePagePath, 'HTMLComplete', (error) ->
|
||||
assert.equal error, null
|
||||
assert fs.existsSync savePagePath
|
||||
fs.unlinkSync savePagePath
|
||||
done()
|
||||
|
||||
w.loadUrl "file://#{fixtures}/api/blank.html"
|
||||
|
|
|
@ -15,9 +15,6 @@ describe 'crash-reporter module', ->
|
|||
beforeEach -> w = new BrowserWindow(show: false)
|
||||
afterEach -> w.destroy()
|
||||
|
||||
# It is not working on 64bit Windows.
|
||||
return if process.platform is 'win32' and process.arch is 'x64'
|
||||
|
||||
# It is not working for mas build.
|
||||
return if process.mas
|
||||
|
||||
|
|
|
@ -450,10 +450,10 @@ describe 'asar package', ->
|
|||
w = new BrowserWindow(show: false, width: 400, height: 400)
|
||||
p = path.resolve fixtures, 'asar', 'web.asar', 'index.html'
|
||||
u = url.format protocol: 'file', slashed: true, pathname: p
|
||||
w.loadUrl u
|
||||
ipc.once 'dirname', (event, dirname) ->
|
||||
assert.equal dirname, path.dirname(p)
|
||||
done()
|
||||
w.loadUrl u
|
||||
|
||||
it 'loads script tag in html', (done) ->
|
||||
after ->
|
||||
|
|
Loading…
Reference in a new issue