Thursday, February 2, 2023
Learning Code
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
Learning Code
No Result
View All Result
Home Swift

Progressive Web Apps on iOS

learningcode_x1mckf by learningcode_x1mckf
September 11, 2022
in Swift
0
Progressive Web Apps on iOS
74
SHARES
1.2k
VIEWS
Share on FacebookShare on Twitter


You might also like

The abstract Vapor service factory design pattern

SwiftNIO tutorial – The echo server

Introducing – Vapor cheatsheet – The.Swift.Dev.

The way to make a PWA for iOS?

A progressive web application is only a particular sort of web site, that may look and behave like a local iOS app. As a way to construct a PWA, first we’ll create an everyday web site utilizing SwiftHtml. We will begin with an everyday executable Swift package deal with the next dependencies.



import PackageDescription

let package deal = Package deal(
    title: "Instance",
    platforms: [
        .macOS(.v12)
    ],
    dependencies: [
        .package(url: "https://github.com/binarybirds/swift-html", from: "1.2.0"),
        .package(url: "https://github.com/vapor/vapor", from: "4.54.0"),
    ],
    targets: [
        .executableTarget(name: "Example", dependencies: [
            .product(name: "SwiftHtml", package: "swift-html"),
            .product(name: "Vapor", package: "vapor"),
        ]),
        .testTarget(title: "ExampleTests", dependencies: ["Example"]),
    ]
)


As you’ll be able to see we’ll use the vapor Vapor library to serve our HTML website. If you do not know a lot about Vapor let’s simply say that it’s a internet software framework, which can be utilized to construct server facet Swift functions, it is a fairly superb software I’ve a beginner’s guide submit about it.


In fact we’ll want some elements for rendering views utilizing SwiftHtml, you should use the supply snippets from my previous article, however right here it’s once more how the SwiftHtml-based template engine ought to seem like. You must learn my different article if you wish to know extra about it. 🤓


import Vapor
import SwiftSgml

public protocol TemplateRepresentable 
    
    @TagBuilder
    func render(_ req: Request) -> Tag


public struct TemplateRenderer 
    
    var req: Request
    
    init(_ req: Request) 
        self.req = req
    

    public func renderHtml(_ template: TemplateRepresentable, minify: Bool = false, indent: Int = 4) -> Response 
        let doc = Doc(.html)  template.render(req) 
        let physique = DocumentRenderer(minify: minify, indent: indent).render(doc)
        return Response(standing: .okay, headers: ["content-type": "text/html"], physique: .init(string: physique))
    


public extension Request 
    var templates: TemplateRenderer  .init(self) 


We’re additionally going to want an index template for our major HTML doc. Since we’re utilizing a Swift DSL to put in writing HTML code we do not have to fret an excessive amount of about mistyping a tag, the compiler will defend us and helps to keep up a very legitimate HTML construction.



import Vapor
import SwiftHtml


struct IndexContext 
    let title: String
    let message: String


struct IndexTemplate: TemplateRepresentable {
    
    let context: IndexContext
    
    init(_ context: IndexContext) 
        self.context = context
    
    
    func render(_ req: Request) -> Tag {
        Html 
            Head 
                Title(context.title)
                
                Meta().charset("utf-8")
                Meta().title(.viewport).content material("width=device-width, initial-scale=1")
            
            Physique 
                Major 
                    Div 
                        H1(context.title)
                        P(context.message)
                    
                
            
        
    }
}


Lastly we are able to merely render the bootstrap our Vapor server occasion, register our route handler and render the index template inside the primary entry level of our Swift package deal by utilizing the beforehand outlined template helper strategies on the Request object.


import Vapor
import SwiftHtml

var env = strive Atmosphere.detect()
strive LoggingSystem.bootstrap(from: &env)
let app = Software(env)
defer  app.shutdown() 

app.get  req -> Response in
    let template = IndexTemplate(.init(title: "Hi there, World!",
                                    message: "This web page was generated by the SwiftHtml library."))
    
    return req.templates.renderHtml(template)


strive app.run()


It’s simply that simple to setup and bootstrap a completely working internet server that’s able to rendering a HTML doc utilizing the ability of Swift and the Vapor framework. In case you run the app you need to be capable to see a working web site by visiting the http://localhost:8080/ deal with.


Turning a web site into an actual iOS PWA

Now if we wish to remodel our web site right into a standalone PWA, we’ve got to offer a hyperlink a particular web app manifest file inside the pinnacle part of the index template.



Meta tags vs manifest.json


Looks as if Apple follows sort of an odd route if it involves PWA help. They’ve fairly a historical past of “considering outdoors of the field”, this mindset applies to progressive internet apps on iOS, since they do not are likely to observe the requirements in any respect. For Android units you would create a manifest.json file with some predefined keys and you would be simply wonderful along with your PWA. Then again Apple these days prefers numerous HTML meta tags as an alternative of the net manifest format.


Personally I do not like this method, as a result of your HTML code will likely be bloated with all of the PWA associated stuff (as you will see that is going to occur if it involves launch display pictures) and I imagine it is higher to separate these sort of issues, however hey it is Apple, they cannot be fallacious, proper? 😅


Anyhow, let me present you how you can help numerous PWA options on iOS.


Enabling standalone app mode


The very first few keys that we would like so as to add to the index template has the apple-mobile-web-app-capable title and you need to use the “sure” string as content material. This can point out that the app ought to run in full-screen mode, in any other case it should be displayed utilizing Safari identical to an everyday website.


struct IndexTemplate: TemplateRepresentable {
    
    let context: IndexContext
    
    init(_ context: IndexContext) 
        self.context = context
    
    
    func render(_ req: Request) -> Tag {
        Html 
            Head 
                Title(context.title)
                
                Meta().charset("utf-8")
                Meta().title(.viewport).content material("width=device-width, initial-scale=1")

                Meta()
                    .title(.appleMobileWebAppCapable)
                    .content material("sure")
            
            Physique 
                Major 
                    Div 
                        H1(context.title)
                        P(context.message)
                    
                
            
        
    }
}


We must always change the hostname of the server and pay attention on the 0.0.0.0 deal with, this manner in case your telephone is on the identical native WiFi community you need to be capable to attain your internet server instantly.


import Vapor
import SwiftHtml

var env = strive Atmosphere.detect()
strive LoggingSystem.bootstrap(from: &env)
let app = Software(env)
defer  app.shutdown() 

app.http.server.configuration.hostname = "0.0.0.0"
if let hostname = Atmosphere.get("SERVER_HOSTNAME") 
    app.http.server.configuration.hostname = hostname


app.get  req -> Response in
    let template = IndexTemplate(.init(title: "Hi there, World!",
                                    message: "This web page was generated by the SwiftHtml library."))
    
    return req.templates.renderHtml(template)


strive app.run()


You will discover out your local IP address by typing the next command into the Terminal app.



ifconfig | grep -Eo 'inet (addr:)?([0-9]*.)3[0-9]*' | grep -Eo '([0-9]*.)3[0-9]*' | grep -v '127.0.0.1'

ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*.)3[0-9]*).*/2/p'


Simply use that IP deal with and go to the http://[ip-address]:8080/ web site utilizing your iOS machine, then you need to be capable to add your web site to your own home display as a bookmark. Simply faucet the Share icon utilizing Safari and choose the Add to Residence Display menu merchandise from the listing. On the brand new display faucet the Add button on the highest proper nook, this may create a brand new icon on your own home display as a bookmark to your web page. Optionally, you’ll be able to present a customized title for the bookmark. ☺️


Since we have added the meta tag, in the event you contact the newly created icon it ought to open the webpage as a standalone app (with out utilizing the browser). In fact the app continues to be only a web site rendered utilizing an online view. The standing bar will not match the white background and it has no customized icon or splash display but, however we’ll repair these points proper now. 📱


Customized title and icon

To offer a customized title we simply have so as to add a brand new meta tag, luckily the SwiftHtml library has predefined enums for all of the Apple associated meta names, so you do not have to kind that a lot. The icon state of affairs is a little more troublesome, since we’ve got so as to add a bunch of measurement variants.


struct IndexTemplate: TemplateRepresentable {
    
    let context: IndexContext
    
    init(_ context: IndexContext) 
        self.context = context
    
    
    func render(_ req: Request) -> Tag {
        Html 
            Head 
                Title(context.title)
                
                Meta().charset("utf-8")
                Meta().title(.viewport).content material("width=device-width, initial-scale=1")
                
                Meta()
                    .title(.appleMobileWebAppCapable)
                    .content material("sure")
                
                Meta()
                    .title(.appleMobileWebAppTitle)
                    .content material("Hi there PWA")
                
                Hyperlink(rel: .appleTouchIcon)
                    .href("/img/apple/icons/192.png")

                for measurement in [57, 72, 76, 114, 120, 144, 152, 180] 
                    Hyperlink(rel: .appleTouchIcon)
                        .sizes("(measurement)x(measurement)")
                        .href("/img/apple/icons/(measurement).png")
                
            
            Physique 
                Major 
                    Div 
                        H1(context.title)
                        P(context.message)
                    
                
            
        
    }
}


As you’ll be able to see icons are referenced by utilizing the Hyperlink tag, utilizing the Apple contact icon rel attribute. The default icon with out the sizes attribute is usually a 192×192 pixel picture, plus I am offering some smaller sizes by utilizing a for loop right here. We additionally have to serve these icon information by utilizing Vapor, that is why we’ll alter the configuration file and allow the FileFiddleware.


import Vapor
import SwiftHtml

var env = strive Atmosphere.detect()
strive LoggingSystem.bootstrap(from: &env)
let app = Software(env)
defer  app.shutdown() 

app.middleware.use(FileMiddleware(publicDirectory: app.listing.publicDirectory))

app.http.server.configuration.hostname = "0.0.0.0"
if let hostname = Atmosphere.get("SERVER_HOSTNAME") 
    app.http.server.configuration.hostname = hostname


app.get  req -> Response in
    let template = IndexTemplate(.init(title: "Hi there, World!",
                                    message: "This web page was generated by the SwiftHtml library."))
    
    return req.templates.renderHtml(template)


strive app.run()


By including the FileMiddleware to the app with the general public listing path configuration your server app is ready to serve static information from the Public listing. Be at liberty to create it and place the app icons underneath the Public/img/apple/icons folder. In case you are working the server from the command line you will be wonderful, however if you’re utilizing Xcode you must specify a custom working directory for Vapor, this may permit the system to lookup the general public information from the appropriate place.


Your customized icons won’t show up if you are using a self-signed certificate.


Construct and run the server and attempt to bookmark your web page once more utilizing your telephone. Once you see the add bookmark web page you need to be capable to validate that the app now makes use of the predefined Hi there PWA title and the picture preview ought to present the customized icon file as an alternative of a screenshot of the web page.


Correct standing bar coloration for iOS PWAs

Lengthy story quick, there’s a nice article on CSS-Tricks about the newest model of Safari and the way it handles numerous theme colours on completely different platforms. It is an excellent article, you need to undoubtedly learn it, however in many of the instances you will not want this a lot data, however you merely wish to help mild and darkish mode to your progressive internet app. That is what I’ll present you right here.


For mild mode we’ll use a white background coloration and for darkish mode we use black. We’re additionally going to hyperlink a brand new type.css file so we are able to change the background of the positioning and the font coloration in line with the present coloration scheme. First, the brand new meta tags to help theme colours each for mild and darkish mode.


struct IndexTemplate: TemplateRepresentable {
    
    let context: IndexContext
    
    init(_ context: IndexContext) 
        self.context = context
    
    
    func render(_ req: Request) -> Tag {
        Html 
            Head 
                Title(context.title)
                
                Meta().charset("utf-8")
                Meta().title(.viewport).content material("width=device-width, initial-scale=1")
                
                Meta()
                    .title(.appleMobileWebAppCapable)
                    .content material("sure")
                Meta()
                    .title(.appleMobileWebAppTitle)
                    .content material("Hi there PWA")
                
                Meta()
                    .title(.colorScheme)
                    .content material("mild darkish")
                Meta()
                    .title(.themeColor)
                    .content material("#fff")
                    .media(.prefersColorScheme(.mild))
                Meta()
                    .title(.themeColor)
                    .content material("#000")
                    .media(.prefersColorScheme(.darkish))
                
                Hyperlink(rel: .stylesheet)
                    .href("/css/type.css")
                
                Hyperlink(rel: .appleTouchIcon)
                    .href("/img/apple/icons/192.png")
                for measurement in [57, 72, 76, 114, 120, 144, 152, 180] 
                    Hyperlink(rel: .appleTouchIcon)
                        .sizes("(measurement)x(measurement)")
                        .href("/img/apple/icons/(measurement).png")
                
            
            Physique 
                Major 
                    Div 
                        H1(context.title)
                        P(context.message)
                    
                
            
        
    }
}


Contained in the type CSS file we are able to use a media question to detect the popular coloration scheme, identical to we did it for the .themeColor meta tag utilizing SwiftHtml.


physique 
    background: #fff;
    coloration: #000;

@media (prefers-color-scheme: darkish) 
    physique 
        background: #000;
        coloration: #fff;
    



That is it, now the standing bar ought to use the identical coloration as your major background. Attempt to swap between darkish and light-weight mode and ensure all the pieces works, there’s a cool PWA demo project here with completely different colours for every mode if you wish to double examine the code. ✅


Splash display help

Trace: it is ridiculous. Splash screens on iOS are problematic. Even native apps are likely to cache the fallacious splash display or will not render PNG information correctly, now if it involves PWAs this is not crucial higher. I used to be in a position to present splash display pictures for my app, however it took me fairly some time and switching between darkish and light-weight mode is completely damaged (so far as I do know it). 😅


As a way to cowl each single device screen size, you must add a lot of linked splash pictures to your markup. It is so ugly I even needed to create a bunch of extension strategies to my index template.


extension IndexTemplate 
    
    @TagBuilder
    func splashTags() -> [Tag] 
        splash(320, 568, 2, .panorama)
        splash(320, 568, 2, .portrait)
        splash(414, 896, 3, .panorama)
        splash(414, 896, 2, .panorama)
        splash(375, 812, 3, .portrait)
        splash(414, 896, 2, .portrait)
        splash(375, 812, 3, .panorama)
        splash(414, 736, 3, .portrait)
        splash(414, 736, 3, .panorama)
        splash(375, 667, 2, .panorama)
        splash(375, 667, 2, .portrait)
        splash(1024, 1366, 2, .panorama)
        splash(1024, 1366, 2, .portrait)
        splash(834, 1194, 2, .panorama)
        splash(834, 1194, 2, .portrait)
        splash(834, 1112, 2, .panorama)
        splash(414, 896, 3, .portrait)
        splash(834, 1112, 2, .portrait)
        splash(768, 1024, 2, .portrait)
        splash(768, 1024, 2, .panorama)
    
    
    @TagBuilder
    func splash(_ width: Int,
                _ peak: Int,
                _ ratio: Int,
                _ orientation: MediaQuery.Orientation) -> Tag 
        splashTag(.mild, width, peak, ratio, orientation)
        splashTag(.darkish, width, peak, ratio, orientation)
    
        
    func splashTag(_ mode: MediaQuery.ColorScheme,
                   _ width: Int,
                   _ peak: Int,
                   _ ratio: Int,
                   _ orientation: MediaQuery.Orientation) -> Tag 
        Hyperlink(rel: .appleTouchStartupImage)
            .media([
                .prefersColorScheme(mode),
                .deviceWidth(px: width),
                .deviceHeight(px: height),
                .webkitDevicePixelRatio(ratio),
                .orientation(orientation),
            ])
            .href("/img/apple/splash/(calc(width, peak, ratio, orientation))(mode == .mild ? "" : "_dark").png")
    
    
    func calc(_ width: Int,
              _ peak: Int,
              _ ratio: Int,
              _ orientation: MediaQuery.Orientation) -> String 
        let w = String(width * ratio)
        let h = String(peak * ratio)
        swap orientation 
        case .portrait:
            return w + "x" + h
        case .panorama:
            return h + "x" + w
        
    


Now I can merely add the splashTags() name into the pinnacle part, however I am undecided if the result’s one thing I can completely agree with. Right here, check out the tip of this tutorial about splash screens, the code required to help iOS splash screens may be very lengthy and I have never even advised you in regards to the 40 completely different picture information that you will want. Persons are actually utilizing PWA asset generators to cut back the time wanted to generate these sort of photos, as a result of it is fairly uncontrolled. 💩


I am utilizing this method in Feather CMS, so if you would like to obtain some pattern information you’ll be able to seize them from GitHub. I am not pleased with splash display help, however hey, it simply works, proper? 🤔


Protected space & the notch


A particular subject I would like to speak about is the secure space help and the notch. I can extremely advocate to learn this text on CSS-Tips about The Notch and CSS first, however the primary trick is that we are able to use 4 environmental variables in CSS to set correct margin and padding values.


First we’ve got to alter the viewport meta tag and lengthen our web page past the secure space. This may be finished by utilizing the viewport-fit cowl worth. Contained in the physique of the template we’ll add a header and a footer part, these areas may have customized background colours and fill the display.


struct IndexTemplate: TemplateRepresentable {
    
    let context: IndexContext
    
    init(_ context: IndexContext) 
        self.context = context
    
    
    func render(_ req: Request) -> Tag {
        Html {
            Head 
                Title(context.title)
                
                Meta()
                    .charset("utf-8")
                Meta()
                    .title(.viewport)
                    .content material("width=device-width, initial-scale=1, viewport-fit=cowl")
                    
                
                Meta()
                    .title(.appleMobileWebAppCapable)
                    .content material("sure")
                Meta()
                    .title(.appleMobileWebAppTitle)
                    .content material("Hi there PWA")
                
                Meta()
                    .title(.colorScheme)
                    .content material("mild darkish")
                Meta()
                    .title(.themeColor)
                    .content material("#fff")
                    .media(.prefersColorScheme(.mild))
                Meta()
                    .title(.themeColor)
                    .content material("#000")
                    .media(.prefersColorScheme(.darkish))
                
                Hyperlink(rel: .stylesheet)
                    .href("/css/type.css")
                
                Hyperlink(rel: .appleTouchIcon)
                    .href("/img/apple/icons/192.png")
                for measurement in [57, 72, 76, 114, 120, 144, 152, 180] 
                    Hyperlink(rel: .appleTouchIcon)
                        .sizes("(measurement)x(measurement)")
                        .href("/img/apple/icons/(measurement).png")
                
                
                splashTags()
            
            Physique {
                Header 
                    Div 
                        P("Header space")
                    
                    .class("safe-area")
                
                
                Major 
                    Div 
                        Div 
                            H1(context.title)
                            for _ in 0...42 
                                P(context.message)
                            
                            A("Refresh web page")
                                .href("https://theswiftdev.com/")
                        
                        .class("wrapper")
                    
                    .class("safe-area")
                

                Footer 
                    Div 
                        P("Footer space")
                    
                    .class("safe-area")
                
            }
        }
    }
}


Besides the background coloration we do not need different content material to movement outdoors the secure space, so we are able to outline a brand new CSS class and place some margins on it based mostly on the atmosphere. Additionally we can safely use the calc CSS operate if we wish to add some further worth to the atmosphere.


* 
    margin: 0;
    padding: 0;

physique 
    background: #fff;
    coloration: #000;

header, footer 
    padding: 1rem;

header 
    background: #eee;

footer 
    background: #eee;
    padding-bottom: calc(1rem + env(safe-area-inset-bottom));

.safe-area 
    margin: 0 env(safe-area-inset-right) 0 env(safe-area-inset-left);

.wrapper 
    padding: 1rem;

@media (prefers-color-scheme: darkish) 
    physique 
        background: #000;
        coloration: #fff;
    
    header 
        background: #222;
    
    footer 
        background: #222;
    



It appears to be like good, however what if we would like to make use of customized kinds for the PWA model solely?


Detecting standalone mode


If you wish to use the show mode media question in your CSS file we’ve got so as to add a manifest file to our PWA. Yep, that is proper, I’ve talked about earlier than that Apple prefers to make use of meta tags and hyperlinks, however if you wish to use a CSS media question to examine if the app runs in a standalone mode you will should create an online manifest.json file with the next contents.



  "show": "standalone"



Subsequent you must present a hyperlink to the manifest file contained in the template file.


struct IndexTemplate: TemplateRepresentable 
    
    
    
    func render(_ req: Request) -> Tag 
        Html 
            Head 
                
                
                splashTags()
                
                Hyperlink(rel: .manifest)
                    .href("/manifest.json")
            
            Physique 
                
            
        
    


Within the CSS file now you should use the display-mode selector to examine if the app is working in a standalone mode, you’ll be able to even mix these selectors and detect standalone mode and darkish mode utilizing a single question. Media queries are fairly helpful. 😍


/* ... */

@media (display-mode: standalone) 
    header, footer 
        background: #fff;
    
    header 
        place: sticky;
        prime: 0;
        border-bottom: 1px stable #eee;
    

@media (display-mode: standalone) and (prefers-color-scheme: darkish) 
    header, footer 
        background: #000;
    
    header 
        border-bottom: 1px stable #333;
    



You possibly can flip the header right into a sticky part by utilizing the place: sticky attribute. I normally want to observe the iOS type when the web site is introduced to the end-user as a standalone app and I preserve the unique theme colours for the net solely.


Do not forget to rebuild the backend server, earlier than you take a look at your app. Since we have made some meta modifications you may need to delete the PWA bookmark and set up it once more to make issues work. ⚠️




Source link

Share30Tweet19
learningcode_x1mckf

learningcode_x1mckf

Recommended For You

The abstract Vapor service factory design pattern

by learningcode_x1mckf
February 1, 2023
0
The abstract Vapor service factory design pattern

I've written a number of articles about manufacturing unit design patterns on my weblog and this time I might like to speak a couple of particular one, which...

Read more

SwiftNIO tutorial – The echo server

by learningcode_x1mckf
January 27, 2023
0
SwiftNIO tutorial – The echo server

Intoducing SwiftNIO In the event you used a excessive degree net framework, corresponding to Vapor, up to now, you would possibly had some interplay with occasion loops...

Read more

Introducing – Vapor cheatsheet – The.Swift.Dev.

by learningcode_x1mckf
January 23, 2023
0
Introducing – Vapor cheatsheet – The.Swift.Dev.

Out there on Gumroad Thanks for supporting my work by buying the cheatsheet. 🙏 Download now A whole Vapor framework reference for novices. greater than...

Read more

iCloud Programming Tutorial for iOS: An Introduction

by learningcode_x1mckf
January 18, 2023
0
iCloud Programming Tutorial for iOS: An Introduction

Editor’s observe: This week, we work with Ziad Tamim once more to provide you an introduction of iCloud programming. You’ll learn to save and retrieve knowledge from iCloud.On...

Read more

Easy multipart file upload for Swift

by learningcode_x1mckf
January 18, 2023
0
Easy multipart file upload for Swift

I imagine that you've got already heard in regards to the well-known multipart-data add method that everybody likes to add recordsdata and submit type knowledge, but when not,...

Read more
Next Post
PayPal Enhances JavaScript SDK with TypeScript Type Definitions – The New Stack

PayPal Enhances JavaScript SDK with TypeScript Type Definitions – The New Stack

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related News

Java Flight Recorder as an Observability Tool

Java Flight Recorder as an Observability Tool

January 27, 2023
Time limit for notify – JavaScript – SitePoint Forums

How can I remove text from a strReviewers string using JavaScript or jQuery? – JavaScript – SitePoint Forums

November 23, 2022
OODA Loop – Magniber Ransomware Adopts JavaScript to Attack Individual Users

OODA Loop – Magniber Ransomware Adopts JavaScript to Attack Individual Users

October 17, 2022

Browse by Category

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

RECENT POSTS

  • Java :Full Stack Developer – Western Cape saon_careerjunctionza_state
  • Pay What You Want for this Learn to Code JavaScript Certification Bundle
  • UPB Java Jam brings coffeehouse vibes to Taylor Down Under | Culture

CATEGORIES

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

© 2022 Copyright Learning Code

No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#

© 2022 Copyright Learning Code

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?