์ค์น
pip install pywebview
Hello world:
import webview
webview.create_window('Hello world', 'https://pywebview.flowrl.com/')
webview.start()
HTML ๋ถ๋ฌ์ค๊ธฐ
url, html ๋ ๋ค ์์ ๊ฒฝ์ฐ html ์ด ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋ค.
import webview
webview.create_window('Woah dude!', html='<h1>Woah dude!<h1>')
webview.start()
HTML ํ์ผ ๋ถ๋ฌ์ค๊ธฐ
import webview
webview.create_window('Woah dude!', 'index.html')
webview.start()
HTTP server
pywebview๋ WSGI ํธํ HTTP ์๋ฒ๋ฅผ ์ ๊ณตํ๋ค. HTTP ์๋ฒ๋ฅผ ์์ํ๋ ค๋ฉด url์ ํ๋กํ ์ฝ ์คํค๋ง ์์ด ๋ก์ปฌ ์ง์ ์ ์ผ๋ก ์ค์ ํ๊ณ start ํจ์์ http_server ๋งค๊ฐ๋ณ์๋ฅผ True๋ก ์ค์ ํ๋ค.
import webview
webview.create_window('Woah dude!', 'index.html')
webview.start(http_server=True)
pywebview์ ํจ๊ป ์ธ๋ถ WSGI ํธํ HTTP ์๋ฒ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์๋ฒ ๊ฐ์ฒด๋ฅผ URL๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ http_server ๋งค๊ฐ๋ณ์๋ฅผ ์ค์ ํ ํ์๊ฐ ์๋ค.
from flask import Flask
import webview
server = Flask(__name__, static_folder='./assets', template_folder='./templates')
webview.create_window('Flask example', server)
webview.start()
Threading model
import webview
def custom_logic(window):
window.toggle_fullscreen()
window.evaluate_js('alert("Nice one brother")')
window = webview.create_window('Woah dude!', html='<h1>Woah dude!<h1>')
webview.start(custom_logic, window)
# anything below this line will be executed after program is finished executing
pass
https://pywebview.flowrl.com/guide/usage.html#basics
https://codingdiary26.tistory.com/20
Application architecture
https://pywebview.flowrl.com/guide/architecture.html#local-web-server
pywebview๋ฅผ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค.
- ๋ก์ปฌ ์น ์๋ฒ ์คํ
- ์๋ฒ๋ฆฌ์ค (JS API or window.expose) and ๋ก์ปฌ ํ์ผ ์ด์ฉ
Local web server
index.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<style type="text/css">
body {
color: #333;
font-size: 14pt;
}
h1 {
font-size: 24pt;
}
</style>
</head>
<body>
<h1>My first pywebview application</h1>
<button onclick="openFolder()">Open folder</button>
<button onclick="toggleFullscreen()">Toggle fullscreen</button>
<button onclick="doStuff()">Do stuff</button>
<div id="open-folder-container"></div>
<div id="stuff-container"></div>
<div id="json-container"></div>
<div style="text-align: center; margin-top: 50px;">
<a href="http://mbsy.co/gHVfC" target="_blank" style="outline:none;border:none;" onclick="openLink(event)">
<img src="https://ambassador-api.s3.amazonaws.com/uploads/marketing/11948/2016_11_29_21_53_43.png" alt="DreamHost" border="0" />
</a>
</div>
<script>
window.token = '{{ token }}';
// Perform background initialization
doAjax("/init", "POST");
function getMethods(obj) {
var result = [];
for (var id in obj) {
try {
if (typeof(obj[id]) == "function") {
result.push(id + ": " + obj[id].toString());
}
} catch (err) {
result.push(id + ": inaccessible");
}
}
return result;
}
function openFolderHandler() {
if (this.responseText) {
var response = JSON.parse(this.responseText);
document.getElementById("open-folder-container").innerHTML = 'Selected directory: ' + response.directory;
}
}
function doStuffHandler(response) {
if (this.responseText) {
var response = JSON.parse(this.responseText);
document.getElementById("stuff-container").innerHTML = response.result;
}
}
function openFolder() {
doAjax("/choose/path", "POST", openFolderHandler);
}
function doStuff() {
doAjax("/do/stuff", "POST", doStuffHandler);
}
function toggleFullscreen() {
doAjax("/fullscreen", "POST", doStuffHandler);
}
function openLink(e) {
e.preventDefault()
var request = {url: e.currentTarget.href}
doAjax("/open-url", "POST", false, request)
}
// From https://gist.github.com/dharmavir/936328
function getHttpRequestObject()
{
// Define and initialize as false
var xmlHttpRequst = false;
// Mozilla/Safari/Non-IE
if (window.XMLHttpRequest)
{
xmlHttpRequst = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject)
{
xmlHttpRequst = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttpRequst;
}
// Does the AJAX call to URL specific with rest of the parameters
function doAjax(url, method, responseHandler, data)
{
// Set the variables
url = url || "";
method = method || "GET";
async = true;
data = data || {};
data.token = window.token;
if(url == "") {
alert("URL can not be null/blank");
return false;
}
var xmlHttpRequest = getHttpRequestObject();
// If AJAX supported
if(xmlHttpRequest != false) {
xmlHttpRequest.open(method, url, async);
// Set request header (optional if GET method is used)
if(method == "POST") {
xmlHttpRequest.setRequestHeader("Content-Type", "application/json");
}
// Assign (or define) response-handler/callback when ReadyState is changed.
xmlHttpRequest.onreadystatechange = responseHandler;
// Send data
xmlHttpRequest.send(JSON.stringify(data));
}
else
{
alert("Please use browser with Ajax support.!");
}
}
</script>
</body>
</html>
Serverless
์๋ฒ๋ฆฌ์ค ์ฑ ์์
start.py
import os
import webview
"""
An example of serverless app architecture
"""
class Api():
def addItem(self, title):
print('Added item %s' % title)
def removeItem(self, item):
print('Removed item %s' % item)
def editItem(self, item):
print('Edited item %s' % item)
def toggleItem(self, item):
print('Toggled item %s' % item)
def toggleFullscreen(self):
webview.windows[0].toggle_fullscreen()
if __name__ == '__main__':
api = Api()
webview.create_window('Todos magnificos', 'assets/index.html', js_api=api, min_size=(600, 450))
webview.start()
setup.py
from distutils.core import setup
import sys
import os
import shutil
def tree(src):
return [(root, map(lambda f: os.path.join(root, f), filter(lambda f: os.path.splitext(f)[1] != ".map", files))) for (root, dirs, files) in os.walk(os.path.normpath(src))]
APP = ['start.py']
DATA_FILES = tree('assets')
OPTIONS_OSX = {'argv_emulation': False,
'strip': True,
'includes': ['WebKit', 'Foundation', 'webview']}
if os.path.exists('build'):
shutil.rmtree('build')
if os.path.exists('dist'):
shutil.rmtree('dist')
if sys.platform == 'darwin':
import py2app
setup(
app=APP,
data_files=DATA_FILES,
options={'py2app': OPTIONS_OSX},
setup_requires=['py2app'],
)
https://github.com/r0x0r/pywebview/tree/master/examples/todos
https://pywebview.flowrl.com/guide/architecture.html#local-web-server