{"id":6033,"date":"2020-02-25T10:08:00","date_gmt":"2020-02-25T09:08:00","guid":{"rendered":"https:\/\/promatis.com\/ch\/building-a-minimal-progressive-web-app-pwa-on-autonomous-apex\/"},"modified":"2023-11-22T12:26:33","modified_gmt":"2023-11-22T11:26:33","slug":"building-a-minimal-progressive-web-app-pwa-on-autonomous-apex","status":"publish","type":"post","link":"https:\/\/promatis.com\/ch\/en\/building-a-minimal-progressive-web-app-pwa-on-autonomous-apex\/","title":{"rendered":"Building a minimal Progressive Web App (PWA) on Autonomous APEX"},"content":{"rendered":"
[et_pb_section fb_built=\"1\" custom_padding_last_edited=\"on|tablet\" disabled_on=\"off|off|off\" admin_label=\"Sektion\" _builder_version=\"4.17.6\" _module_preset=\"default\" custom_padding=\"5vh||5vh||true|false\" custom_padding_tablet=\"5vh||5vh||true|false\" custom_padding_phone=\"5vh||5vh||true|false\" global_module=\"5930\" global_colors_info=\"%91%93\" theme_builder_area=\"post_content\"][et_pb_row column_structure=\"1_4,3_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" custom_margin=\"||0px||false|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_column type=\"1_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_image src=\"https:\/\/promatis.com\/wp-content\/uploads\/2022\/07\/johannes-michler.png\" alt=\"Johannes Michler PROMATIS Horus Oracle\" title_text=\"johannes-michler\" _builder_version=\"4.20.2\" _module_preset=\"default\" width=\"90%\" custom_margin=\"0vh||0vh||true|false\" border_radii=\"on|516px|516px|516px|516px\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][\/et_pb_image][\/et_pb_column][et_pb_column type=\"3_4\" _builder_version=\"4.17.6\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_text ul_type=\"square\" _builder_version=\"4.21.0\" _module_preset=\"default\" link_font=\"Open Sans||||on|||gcid-0becd5ff-19fc-4653-a221-c8c75771a987|\" link_text_color=\"gcid-0becd5ff-19fc-4653-a221-c8c75771a987\" link_font_size=\"22px\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"2vh||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22link_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/p>\n
[\/et_pb_text][et_pb_text ul_type=\"square\" _builder_version=\"4.19.5\" _module_preset=\"default\" link_font=\"Open Sans||||on||||\" link_text_color=\"#00A9A0\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"1vh||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/p>\n
[\/et_pb_text][et_pb_text ul_type=\"square\" _builder_version=\"4.17.6\" _module_preset=\"default\" text_text_color=\"gcid-0becd5ff-19fc-4653-a221-c8c75771a987\" text_font_size=\"22px\" link_font=\"Open Sans||||on||||\" link_text_color=\"#00A9A0\" ul_font=\"Open Sans||||||||\" ul_font_size=\"17px\" ul_line_height=\"1.6em\" header_font=\"|600||on|||||\" header_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_font_size=\"47px\" header_line_height=\"1.2em\" header_2_font=\"|600||on|||||\" header_2_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_2_line_height=\"1.6em\" header_3_font=\"|600|||||||\" header_3_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_3_font_size=\"24px\" header_3_line_height=\"1.4em\" header_4_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_4_line_height=\"1.4em\" header_5_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_5_line_height=\"1.4em\" header_6_text_color=\"gcid-32812186-bc94-4de4-814c-2bf202477fd5\" header_6_font_size=\"16px\" header_6_line_height=\"1.4em\" custom_margin=\"5px||0px||false|false\" custom_padding=\"||||true|false\" text_font_size_tablet=\"20px\" text_font_size_phone=\"17px\" text_font_size_last_edited=\"on|tablet\" header_font_size_tablet=\"\" header_font_size_phone=\"28px\" header_font_size_last_edited=\"on|phone\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22,%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22,%22header_4_text_color%22,%22header_5_text_color%22,%22header_6_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22text_text_color%22%93}\" theme_builder_area=\"post_content\"]<\/i><\/a><\/i><\/a><\/i><\/a>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=\"1\" _builder_version=\"4.16\" _module_preset=\"default\" custom_padding=\"0vh||10vh||false|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_row use_custom_gutter=\"on\" _builder_version=\"4.17.3\" _module_preset=\"default\" custom_padding=\"0px||0px||true|false\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_column type=\"4_4\" _builder_version=\"4.16\" _module_preset=\"default\" global_colors_info=\"{}\" theme_builder_area=\"post_content\"][et_pb_text _builder_version=\"4.21.0\" _module_preset=\"default\" background_enable_color=\"off\" custom_padding=\"0px||0px||true|false\" hover_enabled=\"0\" inline_fonts=\"Times New Roman\" global_colors_info=\"{%22gcid-32812186-bc94-4de4-814c-2bf202477fd5%22:%91%22header_text_color%22,%22header_2_text_color%22,%22header_3_text_color%22%93,%22gcid-0becd5ff-19fc-4653-a221-c8c75771a987%22:%91%22background_color%22%93}\" theme_builder_area=\"post_content\" sticky_enabled=\"0\"]<\/p>\n While there are quite some documentation \/ blogs \/ samples that describe how to build a progressive web app based on Oracle APEX in general, so far there i no real sample that describes in detail on how to build such an app on top of the Oracle Autonomous Database (ATP). This post will give some guidance on how we were able to build a PWA on top of the ATP - in this case even on the \"free tier\" version of ATP on OCI.<\/p>\n In many use cases having a \"mobile\" access to business applications has become crucial. Not always providing just a \"responsive\" layout, e.g. by using the Oracle APEX Universal or a dedicated Mobile-Theme is enough. Nowadays users expect their applications to be available \"from the home screen\" (if not from the App Store), are \"always signed in\", \"offline capable\" and furthermore allow push notifications. Progressive Web Apps can cover most of these requirements (https:\/\/en.wikipedia.org\/wiki\/Progressive_web_application<\/a>).<\/p>\n From a technical perspective the most important parts of a PWA are a manifest.json describing the PWA (and containing e.g. references to a start_url, a logo, ...) and a so called service worker (javascript) that is responsible for especially background notifications and offline usage\/caching.<\/p>\n The www.pwabuilder.com<\/a> websites helps to build your first progressive web app. In a wizard like way you can define all the relevant attributes and further configure a \"caching\" service worker according to your needs. The tool furthermore checks your current configuration for conformance to all the PWA requirements in a nice dashboard.<\/p>\n One crucial requirement for the service worker and the application manifest is: they need to reside in either a dedicated (quite high level, e.g. at root level \/sw.js) URL or they need to provide a special HTTP Header.<\/p>\n On an Oracle Autonomous Database (e.g. ATP) both is difficult to achieve:<\/p>\n There are two possible workarounds for this:<\/p>\n On your ATP instance load the Sample App:<\/p>\n The core files that a progressive web app needs to provide are a manifest.json describing the application in detail and a service worker that implements handling e.g. offline caching and background notifications. An easy way to generate those files is the web app www.pwabuilder.com<\/a>.<\/p>\n The first step on that page is to specify the URL to provide as a PWA. While the pwabuilder can directly check if everything is done correctly (if your app is publicly available) there are currently some issues of this feature for the APEX way of session\/Cookie-Handling (I've created a Pull Request at https:\/\/github.com\/pwa-builder\/PWABuilder\/issues\/630<\/a> to fix this already).<\/p>\n In the manifest tab of pwabuilder fill in the name, icons, start_url, ... of the APEX pwa and save the generated manifest.json:<\/p>\n In addition the \"Service Worker\" tab of the pwabuilder provides a number of pre-built service workers for various caching patterns:<\/p>\n Copy the upper javascript into an app.js and the service worker into sw.js.<\/p>\n Finally zip up the java scripts plus the manifest.json and the icons into a zip that is similar to the one attached here<\/a>.<\/p>\n In the next step upload the above files as \"Static Application Files\". An easy way to load the manifest.json is the favicon section of the apex application:<\/p>\n The app.js that registers the service worker can be put into the \"File Urls\" of the APEX template:<\/p>\n Unfortunately you cannot simple provide the service worker java script as a static application file: It can only handle URLs that lay \"below\" the location of the service worker java script itself. Since this is nested (e.g. \/ords\/r\/test\/100\/files\/static\/v48\/sw.js), this does not allow \"real\" PWA APEX applications. I decided to use ORDS to serve the service worker instead. The implementation can then fetch the actual sw.js from the Application Static Files:<\/p>\n The following articles and demo applications provide examples of PWAs on top of Oracle APEX:<\/p>\n [\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":" Recently my colleague Yves Chassein and myself setup a small Proof of Concept on how to implement a Progressive Web App (PWA) on top of the Autonomous Database (ATP) and APEX.<\/p>\n","protected":false},"author":2,"featured_media":1278,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[440],"tags":[],"dipi_cpt_category":[],"class_list":["post-6033","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-techblog-en"],"_links":{"self":[{"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/posts\/6033"}],"collection":[{"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/comments?post=6033"}],"version-history":[{"count":0,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/posts\/6033\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/media\/1278"}],"wp:attachment":[{"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/media?parent=6033"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/categories?post=6033"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/tags?post=6033"},{"taxonomy":"dipi_cpt_category","embeddable":true,"href":"https:\/\/promatis.com\/ch\/en\/wp-json\/wp\/v2\/dipi_cpt_category?post=6033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}
Senior Vice President<\/strong> \u2013\u00a0Head of Platforms\u00a0&\u00a0Development<\/p>\nProgressive web applications (PWA)<\/h2>\n
pwabuilder.com to kickstart your PWA creation<\/h2>\n
PWAs on Autonomous Database<\/h2>\n
\n
\n
Step by Step to your first PWA on ATP<\/h2>\n
Step1: Install Sample App<\/h3>\n
<\/p>\n
Step 2: Build manifest.json and service worker<\/h3>\n
<\/p>\n
<\/p>\n
<\/p>\n
Step 3: Upload and register manifest and service worker<\/h3>\n
<\/p>\n
<\/p>\n
Step 4: provide the service worker<\/h3>\n
The code for this can look like:<\/p>\n\n
declare\r\nv_clob blob;\r\nbegin\r\napex_session.create_session(p_app_id => 100, --Replace with APP ID\r\np_page_id => 1, --Replace with PAGE ID\r\np_username =>'TEST' --Replace with USERNAME\r\n) ;\r\n\r\nnOWA_UTIL.mime_header('text\/javascript', FALSE);\r\nHTP.p('Service-Worker-Allowed: \/');\r\nOWA_UTIL.http_header_close;\r\nselect blob_content into v_clob from wwv_flow_files where flow_id=100 and filename='sw.js';\r\nWPG_DOCLOAD.download_file(v_clob);\r\nend;<\/pre>\n<\/blockquote>\n
Related Work<\/h2>\n
\n