스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Meet Safari Web Extensions on iOS
Safari Web Extensions use HTML, CSS, and JavaScript to offer people powerful browser customizations — and you can now create them for every device that supports Safari. Learn how to build a Safari Web Extension that works for all devices, and discover how you can convert an existing extension to Safari through Xcode and the Safari Web Extension Converter.
리소스
관련 비디오
WWDC23
WWDC21
- Design for Safari 15
- Develop advanced web content
- Discover Web Inspector improvements
- Explore Safari Web Extension improvements
- Meet privacy-preserving ad attribution
- WKWebView에 추가된 사항 살펴보기
WWDC20
-
다운로드
♪ ♪ Hi. Welcome to Meet Safari Web Extensions on iOS. I'm David Quesada, an engineer on the Safari team. And today, I'll be walking through an exciting new feature in iOS 15, Safari Web Extensions. Web Extensions are a powerful type of browser extension that allows users to extend and customize their browsing in a huge number of ways. They're built with the standard web technologies: HTML, CSS, and JavaScript. And the WebExtension API has been available for all the major desktop browsers for a while, which means you can write a browser extension once and deploy it across all those browsers, reaching so many users. But now, I'm thrilled to tell you that Web Extensions are coming to iOS 15, letting you build a browser extension for more users than ever. I'd love to show you a demo now of a Safari Web Extension running on iOS. I'll be showing off an extension called Sea Creator. This extension was originally written for browsers on the Mac, but I've been working on bringing it to iOS. This extension shows me fun facts about sea creatures and makes reading more about sea life fun by replacing the names of sea creatures with emoji. Let's take a look at this on an iPad. Now, I've just installed Sea Creator, and I've opened up Safari, where I'm reading an article about fish. I'd really love to start using Sea Creator here so I can liven up this page with some emoji. So I'll open up the action menu and drill into the new Extensions list, which shows me all the extensions that I have available, including Sea Creator. So I'll turn it on. Now, another feature of Sea Creator is that I can put it front and center in Safari with a custom Start Page that I use every time I open a new tab. I'll check that out in a bit. And now that I've turned on Sea Creator, it's right there in the Action menu ready for me to use. And when I do that, Safari asks me if I'm OK with giving Sea Creator full access to this site. We brought the same Web Extensions permission model from Safari on the Mac to iOS, which means I, as the user, have full control over how much of my browsing extensions can access. I'll talk in more detail about this later. But right now, I'll allow Sea Creator to run. And just like that, it swapped in all these fish emoji on the page, which is just how I like to read it. It's also opened this popup showing me a running total of just how many words I've replaced so far. But it's not just this one page. I gave Sea Creator permission to work across this website as a whole. So as I navigate to other pages, Sea Creator is still working for me and gives me emoji here as well. I don't need to go out of my way to open the extension again once I've started using it. Of course, Sea Creator has one more feature that I mentioned earlier. When I open up a new tab to do some more browsing, I'm greeted by this bold New Tab page from Sea Creator with a fact of the day today about starfish-- and once again, that counter showing me just how many emoji Sea Creator has given me so far. This is pretty cool. So that was a quick look at Sea Creator working great on iOS. In this session, I want to show how you too can create a Safari Web Extension for iOS. And I'll be using Sea Creator as an example of how I took an existing extension and brought it to iOS with just a few changes. But don't worry if you've never written a browser extension before. I'll give you an overview of how Web Extensions work and how you can get started creating a new one. Along the way, I'll cover some debugging techniques and best practices to help your extension be the best it can be. And I'll wrap it up with some thoughts on user privacy and how it relates to the permissions model of Safari Web Extensions. So, our journey begins with creating a web extension that can run on iOS in the first place. Let's look behind the scenes to understand how this works. It's important to understand that for Safari, Web Extensions are parts of apps. So when you want to install a web extension, you install its app. And like any other type of iOS app, apps with Safari Web Extensions can be found on the App Store. And Xcode has everything you need to build an app to ship your extension. So when you think about building a Safari Web Extension for iOS, you may be starting from one of three places. Maybe you're looking at creating a new extension from scratch, or maybe you already wrote one for another browser, and you want to bring it to Safari, or perhaps you already have an extension for Safari on the Mac, and you want to make it available on iOS too. I want to go over what you can do in each of these cases. So first, if you want to create a brand-new Web Extension, you can use Xcode's included templates, which make it super easy to get started. You can create a new Xcode project and use the Safari Extension App template to start building a web extension as well as its containing app. And when you use this template, you get an extension that comes complete with all the resources a typical web extension might have. You can use this as a starting point by customizing what's already there or adding or removing pieces according to what your extension needs. Now, if you've already built a Web Extension for another browser, you can take advantage of a tool called the Safari Web Extension Converter to automatically create an Xcode project from that existing extension. You simply run the converter on the command line, provide it a path to your extension's resources, and it will create a new Xcode project that packages your extension in a native app. And new in Xcode 13, the Safari Web Extension Converter creates a project that supports Safari on both iOS and macOS by default. And the newly created project, by default, references your existing extension's resources at the original path rather than copying them. Finally, if you've already set up an Xcode project in the past to build a Safari Web Extension for macOS, you can also use the converter to upgrade that project so it supports iOS too. You can run the converter and provide a --rebuild-project option along with a path to your Xcode project. Then the converter will add an iOS-compatible version of the extension and a containing app to your project. Now I want to show the Safari Web Extension Converter in action by retracing my steps of bringing Sea Creator to iOS for the very first time.
So here is my Sea Creator Xcode project, which I used to develop Sea Creator for Safari on the Mac. But it only supports the Mac right now, and I want to fix that. So I'll open up a terminal and type xcrun safari-web-extension-converter, and I'll use the --rebuild-project option, and I'll provide a path to my Xcode project and run the converter. And it confirms some details about my existing project and stops to ask me if I'd like to overwrite it with a cross-platform version. Also, any time you run the converter, it'll warn you about potential compatibility issues with your extension. In this case, it's warning me about the use of something called a persistent background page, which isn't supported on iOS. I'll need to fix this later. But for now, I'll let the converter keep going.
And when it's done, my project automatically opens. Notice there are folders here for both the iOS and macOS versions of my app and the extension. Now, I want to take a look at the Resources folder within the Shared extension group. Here is where I'll find the core pieces of the Sea Creator Web Extension. For those of you who are new to the Web Extension API, I want to explain what some of these pieces are, since I'll be referring to them later. I'll start with the manifest. This is a JSON file that describes the structure of the extension. It includes important information such as the extension's name, which websites it wants to access, and what features it supports, such as a pop-up page or a New Tab page like Sea Creator has. Next, there's a JavaScript source called the background script. The browser can run this script in the background when your extension is enabled, and it allows your extension to listen for various events coming from the browser or other parts of your extension. Sea Creator's background script keeps track of that counter of just how many emoji it's added to web pages. Next, there's another type of script called the content script. The browser automatically runs this script on web pages that the user visits. An extension can have any number of content scripts, and the manifest specifies which content scripts should run on which websites. This script gives your extension the power to extend and customize pages by directly manipulating them. For example, Sea Creator's content page is what actually does the replacement of animal names with emoji. And after it does that, it sends a message to the background script so it can update that central counter. Of course, the extension also has some HTML, CSS, and other JavaScript files for the New Tab page, and that pop-up page as well. And finally, there are some other resources here such as localized strings, as well as the extension's icons and other graphics. So all of these pieces come together to make the Sea Creator Web Extension. And thanks to the Safari Web Extension Converter, I now have a project that packages all of this up into a native app. And I can run my project now, so I can start using Sea Creator in Safari right away. I'll do that now by going to the toolbar at the top of the screen, selecting Sea Creator for iOS, and choosing the destination where I want to run the app. I don't have any iOS devices connected, so in this case, I'll use an iPhone simulator.
I'll then click the Run button. And Xcode will then build my app project, load the simulator, and run my app.
So this is the Sea Creator app generated by the Web Extension Converter, and it contains the Sea Creator Web Extension. At the beginning of this session, I showed that I can turn on extensions directly within Safari, but as the app suggests, I can also use Settings to manage my extensions. And I want to show that off here, so I'll switch to Settings.
I'll jump into Safari, Extensions, and then Sea Creator. And here's the details page for Sea Creator with some info about the extension and a switch to turn it on. But that switch is grayed out, and I can't turn on the extension yet. This means there's a problem with the extension that keeps it from loading. I definitely need to look into this next. And this is where I want to talk about debugging. It's a great first step to just be able to build your project and install your extension, but of course, it's essential to know how to dig deeper to find out why things go wrong if they do. It's easy to identify errors in web extensions and use tools such as Web Inspector to debug parts of your extension, and that's what I'll show you now. Looking back at Settings, there's an error here at the bottom telling me that Extensions on iOS must have a non-persistent background page. This sounds familiar. It's the same issue the converter warned me about earlier. And now I want to actually go fix it. So I'll go back to Xcode, open up the manifest, and add a "persistent": false key in the background section. I'll talk about this change in more detail later, but for now, this should get me past the error. Now that I've made this change, I'll run the app again to install the updated extension on the simulator.
And here's the Sea Creator app once again. It looked like I only had that one error to fix, so now I'll go straight to Safari instead of going back to Settings.
I'll open up Safari, open the Extensions list, and there's Sea Creator, and it looks like I can turn it on now. Safari offers me the choice to use Sea Creator's New Tab experience. And I do want to check out what that looks like on iPhone since I haven't seen it before. So I'll set that as my New Tab page, close out the Extensions list, and open up a new tab. And just as I'd expect, there's that New Tab page from Sea Creator. But the text is really small, and the page just doesn't look good. This is the first time I've ever run this extension on iOS, so it's not surprising that the content hasn't yet been adjusted to work well with iPhone. I want to go fix this now, and to do that, I'll use Web Inspector to take a closer look at this page and try out a few changes I have in mind. So to get to Web Inspector, I'll open up Safari on my Mac, and then I'll double-check in Safari's Advanced Preferences to make sure I have the Develop menu enabled.
And now that I have that Develop menu, I can open it up, select the iPhone Simulator I've been using, and choose a page to inspect. Now, there are two options here for Sea Creator. I could select the Extension Background Page if I'd like to debug the background script, but in this case, I want to inspect the New Tab page. So I'll choose the other option.
And now I'm in Web Inspector. The first thing I want to address here is the overall size of the page. By default, Safari on iPhone renders the web page as if it were the size of a desktop browser, and then it scales that larger content down so it all fits on screen. But I don't want this behavior here since it makes the text too small. So I'll use a very common practice when it comes to web design for iPhone. I'll add a viewport meta-tag to tell Safari not to scale the content this way. I'll select the Head element, add a Child element, and add the contents of that viewport meta-tag. I'll add the tag, and the page updates live in the simulator in response to that change. Now all the text is at a readable size, but it doesn't all fit on screen, which is my next problem. I want to inspect the elements on this page to understand why it lays out like this.
I'll look at the body tag, and I notice there's this div here that contains all the content on the page. If I focus it and look in the stylesheet sidebar to the right, I notice that the element has a fixed width of 850. That would make sense on a desktop, where windows can be really wide and you'd want the text to wrap at some point. But that doesn't work on iPhone because the phone just isn't that wide. I think it would make more sense here if that rule set a maximum width for the content rather than demanding an exact width. And I can simply edit the rule here. I'll click width and change it to max-width, and the page in the simulator updates to reflect that change. Now the content's width is much more appropriate for iPhone, and all of the text fits on screen. This looks much better now, but these changes that I've made are only temporary to this Inspector session. I want to actually save these changes back into my project so I don't lose them. And it's really easy to save an updated copy of the stylesheet while I work in the stylesheet Inspector. I can simply type Command+S to save my stylesheet that has that updated rule. And I'll overwrite the new_tab_page.css in my project.
But for the viewport change, I added that tag to a live web page rather than a static resource, so I'll have to make the same change to the original source. I'll select that tag, copy it, go back to Xcode, open up that source for the New Tab page, and paste the contents there.
So the next time I run Sea Creator, it'll use that updated page source and stylesheet, and it'll look just as good again. And that's been a few examples of using Web Inspector to look under the hood of a web extension, understand exactly what's happening, and experiment with potential changes while iterating on the extension. For now, I'm only going to look at the New Tab page, but later on in development, I should obviously go test all the other parts of the extension on iOS, and I'd use the same tools and techniques for that. You can use Safari's extension settings on iOS to view any errors in the configuration of your Web Extension. Specifically, Sea Creator had the fatal error of using a persistent background page, but there may also be non-fatal warnings here that you should check out. These details will only appear in Settings for debug builds of your app from Xcode and not for copies from the App Store or TestFlight.
As you make changes to your web extension, you simply run your app again to update the extension on the device or simulator. And of course, Web Inspector allows you to investigate issues with your extension's web content. Remember that in order to access Web Inspector, I had to enable the Develop menu in Safari's Advanced Preferences on the Mac. In my demo, I used the iOS simulator for my extension, but if you wanted to use a physical iOS device, you would also need to enable Web Inspector support on that device in Safari's Advanced Settings. To take a deeper dive into Web Inspector and learn about some of its newest features, check out Discover Web Inspector improvements. Now that I've created a Safari Web Extension for iOS and I've debugged a few basic issues, I'd like to walk through some best practices to keep in mind, including some things you might need to watch out for as you build an extension for Safari on iOS. I'll focus on five topics that may be relevant to your extension, starting with non-persistent background pages. The background page is a web page that the browser loads to run your extension's background script. And this page allows your extension to handle events sent by the browser or other parts of your extension. But keeping this page loaded has a performance cost. It can use memory and power as if you were keeping one more tab open and running for every enabled extension. Keeping all these pages loaded all the time can be pretty wasteful. But you can make a background page non-persistent, which means the browser will only load it when your extension actually needs to do work, and the browser can later unload that page when it's been idle for some time. That way, the performance cost is only paid while your extension is doing something useful. This is important because background pages must be non-persistent on iOS, where system memory and battery life are especially at a premium. The web extension templates in Xcode already come with a non-persistent background page, so they're ready to run on iOS. But if you have an existing extension that uses a persistent background page like Sea Creator did, you'll need to change it to be non-persistent. And you can do that by adding that "persistent:" False key in the background section of your manifest. To learn more about some best practices and potential issues you may face when updating an extension to use a non-persistent background page, check out Explore Safari Web Extension Improvements. Up next, let's talk about responsive design. As we learned with Sea Creator, bringing an extension to iOS means its web content may be rendered in new environments that you haven't considered before. Just like I did with Sea Creator's New Tab page, be sure to test the layout of your extension's web content on iPhone and iPad and use a responsive design that can accommodate various screen sizes. But the difference in screen size isn't the only consideration when it comes to making your web content look great on iOS. Let me tell you about a few things you should be aware of. If your extension has full-page web content that lays out important elements near the bottom of the screen, you may find it being covered by Safari's Tab Bar or the device's home indicator. In CSS terminology, this area near the edge of the screen where content may be partially hidden is called the unsafe area, while the usable area of the viewport is called the safe area. By using CSS environment variables, you can calculate the safe area inset to make sure important elements are positioned within the safe area. On iPhone, this is also worth considering in Landscape, where devices may have safe area insets on the left and right side of the display as well. By using similar CSS and by specifying the viewport-fit parameter in your viewport, you can give your web content an edge-to-edge design that still keeps important content within the safe area.
Check out Design for Safari 15 to learn more about these APIs that can make your web content feel more at home on iOS. On iPad and desktop browsers, if your extension has a pop-up page, you may be used to it being shown as a popover that's comfortably sized to fit its content. But on iPhone, however, Safari will display this web page as a sheet, which may be a surprise to your content. The sheet spans the full width of the device, and it may be laid out taller than the content expects. In this screenshot of an early version of Sea Creator, the content didn't have much padding from the edge of the screen, and we set a background color on an individual element in the page rather than on the body. So the text looks a bit cramped and the background doesn't fill the whole page. But we've since updated the alignment and padding of the content to give it a little more space to breathe, and we now specify a background color on the body so it covers the whole sheet. If your extension has a pop-up page, think about whether you should make similar changes for your extension. And note that Safari will use a similar presentation in Landscape as well. Be sure to test your extension's interface in these configurations to make sure its layout makes sense when given this extra space. And finally among the design considerations, I want to mention Dynamic Type. Dynamic Type is a feature that allows users to adjust the size of text and other visual elements. You can make content smaller to fit more or larger so it's more visible. Be sure to test your extension's interface under smaller or larger text sizes to make sure it looks all right with any size the user chooses. To help your web content make the most of Dynamic Type, WebKit has a variety of system fonts that respect the user's text size preference and resize to match. You should adopt these fonts in your extension so that its text remains comfortably readable to the user, just like the rest of Safari's interface. So the main takeaway here is to design your extension's web content with Safari's UI in mind. Test any full page web content on iPhone to make sure that it adapts well to the screen size and doesn't clash with Safari's UI at the bottom of the screen. You should test your pop-up web page on iPhone to make sure its layout makes sense with the sheet-style presentation, and you should test your interface across a wide range of Dynamic Type sizes to make sure it adjusts for the user's preference. For more tips on designing web content to look great in Safari's new interface, check out Design for Safari 15. Up next, pointer events.
If your extension currently depends on handling mouse events for arbitrary clicks and drags, be aware that the same events won't be sent when the user taps on iOS. You should instead adopt the Pointer Events API. It's similar to the Mouse Events API, and it works just the same with mouse input, but the Pointer Events API also reports touches and Apple Pencil input. And now let's talk about the Web Extension Windows API. On desktop browsers, users may have multiple windows open and your Web Extension can use the browser.windows API to work with these windows. And the same is true on iPad, where you can also open multiple windows of Safari. Each Safari window might be full screen, or it might be in split view, side-by-side with another app, maybe another Safari. Under the hood though, each of these windows is actually called a scene on iOS. If your extension uses the Windows API, you should know that each scene of Safari actually has two windows: one for regular browsing and one for Private browsing. This is also true on iPhone, even though there's only one scene of Safari. If I call the browser.windows.getAll API to query what windows are open, then the API returns these two window objects. In the first window, the incognito property is false, and focused is true. This represents the window I'm looking at, which is in regular browsing and not Private Browsing. The second window holds the Private Browsing tabs in the Safari scene. And of course, its properties are different from the first window. Incognito is true, and focused is false. Now when I switch Safari to Private Browsing and call windows.getAll again, the API returns different window objects. Now the focused property has changed in both windows, and the second window now has focus.
This works exactly the same on iPad where one Safari scene is represented by two windows. But if I open a second scene of Safari in split view, the API would now report four windows. And if my extension listens for the windows.onCreated event, it would observe that event fire twice when opening split view, once for each of the two new windows in the new Safari scene. So if you use this API, keep this model in mind as you encounter extra windows you might not expect at first. In addition to this model of what a window actually is, there are a few limitations of the windows API that may affect your extension. The methods to create, remove, and update the state of windows aren't available. On iOS, window placement is fully controlled by the user, not any app or extension. The windows.onRemoved event won't be fired as you'd maybe expect when the user closes Safari from the app switcher. That doesn't truly close or remove a window. It just leaves it for the user to pick up where they left off later. And note that these restrictions only apply to the windows themselves and not the tabs within those windows. With the browser.tabs API, Web Extensions still have full control to add, remove, and update individual tabs as they'd like. Now, last up in the best practices is feature detection. When bringing an existing extension to iOS, you may find some APIs are unavailable-- for example, the windows APIs that I mentioned a moment ago. But there are a few others, like context menus and WebRequest. If non-essential parts of your extension use such APIs, be sure to use feature detection to handle the case that they're not available. So, instead of unconditionally calling these APIs, conditionalize that code based on the existence of those APIs, so you can cleanly exclude parts of your extension and make it more flexible when it comes to which browsers it supports. You should also use this pattern when adopting new APIs that are added in the future, as they might not immediately be available across all browsers or in previous versions of browsers that some users may still be using. And that wraps up the best practices. I've now covered many parts of Safari Web Extensions, but I've saved arguably the most important topic for last, and that's user privacy. User privacy is a huge part of everything we do, so we believe users deserve transparency and control when it comes to how their personal data is handled. And of course that includes everything they do in Safari. Web Extensions can gain a tremendous amount of access to the user's browsing, so the decision of whether that should be allowed and on which websites should be up to the user. Historically, other browsers would give an extension full access to every website it requests right away when you turn it on, which is potentially asking you to sacrifice privacy up front just to get a taste of the extension. But Safari aims to do better by providing transparency and control to Web Extension users with an opt-in model where extensions are only given access to websites when the user consents. You caught a glimpse of this earlier with Sea Creator. It didn't immediately start modifying my pages when I turned it on, but it was only able to do that when I explicitly told Safari, "Yes, I want to use this extension here, and I'm okay with it having access." And once I give an extension that access, Safari tells me in the Tab Bar that I have an extension running on this page, so I know that the extension might be seeing my web browsing here. But if I navigate to any website that I haven't yet allowed the extension to access, that indicator disappears. And I know that that extension isn't running on this page and can't see what I'm doing here. Let's look at this permissions model in more detail. Again, users opt in to your extension when they choose to use it on specific websites. Safari will ask the user for consent by presenting a dialog which makes it clear which websites the extension is trying to access. This happens when the user invokes your extension by selecting it in the Action menu or by using any of its keyboard shortcuts. And this consent is required for any privacy sensitive API to work. Specifically, any API that reveals the URL or title of a tab will only include this info if your extension has permission for that URL. The Cookies API will only let your extension read and write cookies for websites your extension has permission for. And injecting JavaScript and stylesheets will only be allowed on websites where, you guessed it, your extension has permission.
If your extension's scripts call any of these APIs when your extension doesn't have the required permissions but hasn't asked the user yet, Safari will wait to call your completion handlers and will show a non-disruptive banner at the top of the screen. This lets the user know that your extension wants some more access, and they can then review the set of websites your extension is asking for, and they can make a decision to allow or reject access for those websites. You should avoid requesting more permission this way than your extension really needs. For some types of extensions, this way of thinking about permission might be a bit more than you need. For example, extensions that share or annotate individual web pages don't need full access to the site any time the user visits in any tab, but rather they just want permission once to do one thing at a time for the user.
And there's a great solution for those extensions called the activeTab permission. When your extension requests the activeTab permission, Safari will automatically grant your extension permission on tabs where the user explicitly uses your extension. And this permission will be limited to just the current website in just the current tab. So it'll be revoked if the user navigates that tab to a different website. Safari won't display a prompt when granting this permission, since there's no long-term commitment needed from the user.
To adopt this feature, simply add activeTab to the Permissions section of your manifest.
So all of this is to say that in Safari, users are always in control of which websites their extensions can work on. So be aware that your extension won't automatically be able to go to work on every page the user visits. For many extensions, the activeTab permission is a great way to get access to just the pages where the user is using your extension without bugging them about any access beyond that. All of these concepts are the same across all our platforms that support Safari Web Extensions. To see this in action on macOS and get a closer look at updating an extension to use activeTab, check out Meet Safari Web Extensions from WWDC 2020. And that's the privacy preserving permissions model of Safari Web Extensions. Along with everything else I've covered today, I hope this gives you a more complete view of Safari Web Extensions on iOS and the tools available to you for building them. We're so excited to see the Web Extension experiences that will be brought to Safari on iOS 15, including the many extensions we already love on the Mac today but also the great new extensions that are yet to come. So if you're new to extension development, I encourage you to check out the linked resources associated with this session. There, you'll find sample code that you can download and try out for yourself. And you can read more about the Web Extension APIs available to you in Apple's developer documentation and the MDN Web Docs. If you already develop a Web Extension for another browser or for Safari on the Mac, I encourage you to try out the Safari Web Extension Converter in Xcode 13 to easily bring your extension to iOS. If you have feedback like bug reports, suggestions, or compatibility issues, I encourage you to send us that feedback at feedbackassistant.apple.com. You can also reach out to us at the Apple Developer Forums if you'd like to get in touch or have questions. And finally, I'd like to again recommend two other sessions you may be interested in. Explore Safari Web Extension Improvements will teach you about some recent API additions to Safari Web Extensions. And Design for Safari 15 will show you how to make your web content look great with Safari's new design in iOS 15. Thanks for watching, and have a great WWDC. [upbeat music]
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.