如何开发一个 Safari 插件

078d8c125c216a46bd095517b69202bc.jpeg

aac3518b2e65bd64a923bcf5c6df156d.gif

本文字数:2493

预计阅读时间:15分钟

88d342aaa21f1597b023cda801fc4913.png

由于常用浏览器是Safari,而Safari浏览器的插件比不上Chrome,所以就有了自己开发常用的Safari插件的想法。

打算开发当前页面生成二维码的Extension,因为网络原因,AirDrop有时候搜不到手机,所以有了这个需求,而且这个也比较简单,所以从这个开始。

01

调研

苹果的官方文档 safari_web_extensions 给出了步骤,看了好几遍,还是不知道如何下手。虽然新建项目的时候苹果帮忙把框架已经都建好了,但是还是有疑惑,疑惑的点在于:

  • 主APP的作用是什么?

  • Extension的作用是什么?

  • 代码应该写在哪里?

  • manifest.json支持的配置项有哪些,哪里可以看到,应该设置哪些?

  • content.js、background.js分别是干什么用的,什么时候用?

  • popup.html、popup.css、popup.js又是指的哪部分?

  • content.js、background.js、popup.js中操作tab的方法有哪些?哪里可以看到?

这些疑惑一度导致开发计划搁浅,因为没有文章来解释这些问题。于是转而去Github上找有没有SafariExtension的代码,看其他人是如何实现的?搜到了 ADGuardForSafari 等等很优秀的Extension,但是项目太大了,对于还没入门的笔者来说,解答不了上面的疑惑。

02

解决

直到偶然看到 QR Code Extension 这个,下载对比官方文档各个文件的解释,笔者终于对上面的疑惑有了答案,终于能动手开发自己的Extension了。

  • 主APP的作用是定义Extension的设置(配置项),如果开发简单的 Extension,比如二维码生成、json格式化等不需要自定义设置的,主APP不需要修改;

  • Extension的是实现插件的实际地方,代码应该写在这里,这里面的代码是 html和js的内容和原生开发没太大关系;

  • manifest.json支持的配置项可以看 Assessing your Safari web extension’s browser compatibility  Browser compatibility for manifest.json,有初步印象即可,然后可以参照其他项目,再根据实际情况决定manifest.json里设置哪些;

  • content.js可以理解为注入到当前打开Tab页面的js,background.js则是Tab不活跃时的,如果不涉及不活跃Tab,则 background.js中无需实现;

  • popup.html、popup.css、popup.js指的是点击 Extension 按钮时,出现的下拉界面;

  • 操作tab的方法可以参考 Manage tabs,把里面chrome.tabs改为browser.tabs来调用即可。

03

手把手开发一个当前页面链接生成二维码的插件

选中Xcode -> File -> New -> Project, 然后选中Multiplaform -> Safari Extension App,选中Multiplaform代表同时支持iPhone和Mac,如下图:

d4dc105e517da2b84511ffb22df18ac0.png

下一步,输入项目名称,选择语言,如下图:

d731756d8feee3da2397cecde1fbe491.png

然后选择存储地方,保存,项目会自动打开,结构如下,可以看出,分为几个部分:

  • Shared (App)

    • Main.html

    • Icon.png

    • Style.css

    • Script.js

    • ViewController.swift:Mac/iOS APP的主界面,其中是一个webview 加载Resources下的Main.html;这个类可以不修改;如果有从APP中自定义Extension设置选项的功能,则需要修改;

    • Assests.xcassets:Mac/iOS APP的图标,可以用AppIconGenerator 来一键生成(Ps: 开发了两个ExtensionAPP,生成图标有点麻烦,所以干脆开发了一个,欢迎使用);

    • Resources

  • Shared (Extension)

    • _locales

    • images

    • manifest.json

    • background.js

    • content.js

    • popup.html

    • popup.css

    • popup.js

  • iOS (App)

  • macOS (App)

  • iOS (Extension)

  • macOS (Extension)

f353c1a8be922535e10d232de31e9694.png

再来考虑一下要做的界面: 初步设想是一个最简单的,点击Tab栏的Icon,展开生成一个当前页面链接的二维码。

然后来看下如何实现:

首先配置manifest.json中的设置项,因为插件的功能是对所有网页都生效,所以修改content_scripts中的matches为所有网页,且配置host_permissions所有网页;另外需要获取当前活跃的Tab,所以在permissions中添加配置,最终要修改的配置项如下:

{..."content_scripts": [{"js": [ "content.js" ],"matches": [ "http://*/*", "https://*/*", "<all_urls>" ]}],"host_permissions": ["http://*/*", "https://*/*"],"permissions": ["activeTab","tabs","scripting","messaging"]
}

然后来考虑界面,用接口生成二维码图片然后加载显示的方式,需要有一个 loading,然后一个放置图片的地方;所以在popup.html中修改如下:

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><link rel="stylesheet" href="popup.css"><script type="module" src="popup.js"></script>
</head>
<body><div id="loader"></div><div id="img_back"><img id="qrcode" src=" " alt="QR Code" /></div>
</body>
</html>

然后popup.css中设置loading动画和界面布局,代码如下:

:root {color-scheme: light dark;
}body {width: 360px;height: 360px;font-family: system-ui;text-align: center;margin: 0;background-color: white;
}#loader {position: absolute;left: 50%;top: 50%;z-index: 1;width: 120px;height: 120px;margin: -76px 0 0 -76px;border: 16px solid #f3f3f3;border-radius: 50%;border-top: 16px solid #3498db;-webkit-animation: spin 2s linear infinite;animation: spin 2s linear infinite;
}@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }
}#img_back {display: block;position: absolute;left: 50%;top: 50%;z-index: 1;width: 320px;height: 320px;margin: -160px 0 0 -160px;}#qrcode {width: 100%;border-radius: 9px;
}

然后来考虑js的实现,点击Tab栏的Icon,直接触发生成二维码的方法,具体步骤如下:

  1. 查询所有Tab

  2. 获取正在显示的Tab

  3. 获取正在显示Tab的链接

  4. 用链接发起生成二维码的请求,然后显示在img上

这里需要注意的是第三步,获取正在显示的Tab的链接,需要在content.js中获取,所以就需要通过方法通信,触发content.js获取当前的链接,然后再从content.js中回传给popup.js中,因为最终显示是在popup.html中,所以需要通过popup.js来发起请求。popup.js中代码如下:

const kQRAPI = "https://qrcode.tec-it.com/API/QRCode?data="function generateQRCode(methodName, message) {// 查询所有 Tabbrowser.tabs.query({ active: true, currentWindow: true }, function (tabs) {// 获取当前正显示的 Tabvar activeTab = tabs[0];// 发消息给 content.js,告诉它获取当前链接browser.tabs.sendMessage(activeTab.id, { title: methodName, message: message}, function (res) {// content.js 获取后回调到这里if (res.title == "targetURL") {const activeTabURL = res.urlStr;const encodedTabURL = encodeURIComponent(activeTabURL);// 获取popup.html 中 imgvar qrcodeImg = document.getElementById("qrcode");qrcodeImg.onload = function() {// 图片加载完成,loading 消失document.getElementById("loader").style.display = "none";};// 通过请求获取二维码照片qrcodeImg.src = kQRAPI + encodedTabURL + "&istransparent=true";}});});
}// 直接触发生成二维码的方法
generateQRCode("getPageURL", "generate current page URL");

content.js中代码如下:

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {console.log("Received request: ", request);// 接收 popup.js 中发送的消息,并回调结果if (request.title == "getPageURL") {sendResponse({ title: "targetURL", urlStr: window.location.href });}
});

然后选择 macOS运行,如下图:

79d1a31b5a0a4be330778da88280bd20.png
选择 macOS

效果如下:

cee12b8d4888431b26f9fb1409d2c3d7.gif

loading生成二维码

然后来考虑优化,通过请求生成二维码依赖网络环境,如果网络环境不好,可能loading时间过长,甚至失败,那么能不能不通过请求,直接生成二维码?

答案是可以的,参考Chrome上的QR Code Generate,点击后马上就生成二维码,如下:

924c1be5b9d0050e5a780f174d448188.gif

Chrome QR Code Generate

所以是可以优化的,通过js直接生成二维码,而不需要依赖网络。最终效果如下:

1ac62a0f70bb47c911eee53ae4e6eeeb.gif

GenerateQR-Extension

插件已上架到商店,名字为 [GenerateQR-Extension],欢迎体验。希望大家通过上面的介绍都能开发自己常用的 Safari-Extension。

参考:

  • safari_web_extensions(https://developer.apple.com/documentation/safariservices/safari_web_extensions)

  • chrome_web_exrensions(https://developer.chrome.com/docs/extensions/mv3/getstarted/extensions-101/)

  • Assessing your Safari web extension’s browser compatibilityhttps://developer.apple.com/documentation/safariservices/safari_web_extensions/assessing_your_safari_web_extension_s_browser_compatibilit)

  • Browser compatibility for manifest.json

    (https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_compatibility_for_manifest.json)

  • QR Code Extension

    (https://github.com/NiklasGabriel/QR-Code)

  • LSApplicationCategoryTypehttps://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/167685.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DASCTF-CBCTF-2023 Crypto部分复现

文章目录 EzRSACB backpack 这次比赛没打&#xff0c;记错时间了&#xff0c;看了一下&#xff0c;如果去做的话大概也只能做出那两道简单的题&#xff0c;还是太菜啦 EzRSA 题目描述&#xff1a; from Crypto.Util.number import * import random from gmpy2 import * from …

屏幕截图软件Snagit 2023 mac中文特点介绍

Snagit 2023 mac是一款屏幕截图和视频录制软件&#xff0c;它可以帮助用户快速捕捉屏幕上的任何内容&#xff0c;并将其编辑、标注和共享。 Snagit 2023 软件特点 多种截图模式&#xff1a;支持全屏截图、窗口截图、区域截图、延时截图等多种截图模式&#xff0c;满足不同用户…

机器学习笔记 - 深度学习中跳跃连接的直观解释

一、概述 如今人们利用深度学习做无数的应用。然而,为了理解在许多作品中看到的大量设计选择(例如跳过连接),了解一点反向传播机制至关重要。 如果你在 2014 年尝试训练神经网络,你肯定会观察到所谓的梯度消失问题。简单来说:你在屏幕后面检查网络的训练过程,你看到的只…

STM32+2.9inch微雪墨水屏(电子纸)实现显示

本篇文章从硬件原理以及嵌入式编程等角度完整的介绍了墨水屏驱动过程&#xff0c;本例涉及的墨水屏为2.9inch e-Paper V2,它采用的是“微胶囊电泳显示”技术进行图像显示&#xff0c;其基本原理是悬浮在液体中的带电纳米粒子受到电场作用而产生迁移&#xff0c;从而改变显示屏各…

第63讲:MySQL存储过程变量传参的核心概念与案例

文章目录 1.存储过程传参2.存储过程传参的语法结构3.存储过程传参经典案例3.1.IN类型的传参3.2.IN和OUT同时使用的传参3.3.INOUT类型的传参 1.存储过程传参 在创建存储过程时&#xff0c;存储过程名称后面的括号里是可以传入一些参数的&#xff0c;例如传入一个变量&#xff0…

OpenCV+QT实现的数字图像处理算法合集

源码下载地址&#xff1a; 基于OpenCV和QT的图像处理源码 图像预处理 灰度处理 灰度直方图 灰度均衡 梯度锐化 Laplace锐化 边缘检测 Roberts Sobel Laplace Prewitt canny Krisch 噪声 椒盐噪声 高斯噪声 滤波 均值滤波 中值滤波 双边滤波 形态学滤波 高斯滤波 图像变…

CMMI V2.0能力域

1、概念 能力域是一组相关的PA&#xff0c;可以提高组织或项目的技能和活动的性能。能力域视图是CMMI模型的一个子集&#xff0c;描述了构成特定能力域的一组预定义PA。能力域是一种视图。如下面规划和管理工作能力域视图&#xff1a; 2、类别 类别是相关能力域的逻辑组或视图…

UnitTest框架的使用

文章目录 一、UnitTest框架是什么&#xff1f;二、UnitTest核心要素三、TestCase四、TestSuite & TestRunner 一、UnitTest框架是什么&#xff1f; UnitTest框架是python自带的一个单元测试框架&#xff0c;主要用它来做单元测试&#xff0c;它有以下特点&#xff1a; 能…

UE4 UltraDynamicSky 天气与水体交互

最上面的Lerp的A通道为之前的水面效果&#xff0c;B是做的冰面效果 用Dynamic_Landscape_Weather_Effects的BaseColor的R通道四舍五入作为Lerp的Alpha值 使用一张贴图&#xff0c;乘以RadialGradientExponential对材质边缘做弱化&#xff0c;RadialGradientExponential的Raid…

SpringBoot项目访问后端页面404

检查项目的路径和mapper映射路径没问题后&#xff0c;发现本级pom文件没有加入web启动模块的pom文件中 maven做项目控制时&#xff0c;要注意将maven模块加入到web启动模块中

YOLOv8改进实战 | 更换主干网络Backbone(四)之轻量化模型MobileNetV3

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

Linux tmux使用总结

文章目录 1 tmux介绍2 tmux概念会话Sessions、窗口Windows、面板Panesstatus line中字段含义 3 Sessions会话管理新建会话断开当前会话进入之前的会话关闭会话查看所有的会话 4 tmux快捷指令系统指令窗口&#xff08;Windows&#xff09;指令面板&#xff08;Panes&#xff09;…

【C++进阶(九)】C++多态深度剖析

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 多态 1. 前言2. 多态的概念以及定义3. 多态的实…

java 企业工程管理系统软件源码 自主研发 工程行业适用

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…

英语——分享篇——每日200词——3001-3200

3001——ascertain——[ˌsəteɪn]——vt.查明&#xff0c;弄清——ascertain——a苹果(编码)s美女(编码)certain确定(熟词)——吃苹果的美女确定已查明此事——It can be difficult to ascertain the facts. ——可能难以查明事实真相。 3002——disrupt——[dɪsrʌpt]——…

spring6-国际化:i18n | 数据校验:Validation

文章目录 1、国际化&#xff1a;i18n1.1、i18n概述1.2、Java国际化1.3、Spring6国际化1.3.1、MessageSource接口1.3.2、使用Spring6国际化 2、数据校验&#xff1a;Validation2.1、Spring Validation概述2.2、实验一&#xff1a;通过Validator接口实现2.3、实验二&#xff1a;B…

Python 安装CSF(布料模拟滤波)的环境配置

一、环境配置 1.1 下载源码: Github下载CSF库源码 1.2 解压文件如下: 二、安装CSF库 2.1在解压文件中找到python文件夹所在目录 2.2 输入cmd并回车,来打开终端窗口 2.3激活虚拟环境 通过: activate +你的虚拟环境名称。来激活安装CSF库的虚拟环境。【不执行此

VM16Pro的Win10虚拟机安装Linux子系统Kali

VM16Pro的Win10虚拟机安装Linux子系统Kali 一、启用Windows功能二、配置WSL三、安装Kali四、安装kali基本工具包五、图形化六、适用的报错七、其他问题参考 一、启用Windows功能 启用后需重启二、配置WSL wsl --update #管理员启动Powershell执行&#xff0c;完成后将下面…

GitLab-访问返回403 forbidden问题处理

访问gitlab时报错forbidden 一般访问量大&#xff0c;密码错误频率高的时候&#xff0c;gitlab防爆机制启动了&#xff0c;对IP做了封禁&#xff0c;导致某些IP访问的是否返回 403 forbidden 1. 查看被封的IP /opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/red…

vant组件是使用?

首先 在vue项目中使用的时候 要先下载组件 使用npm安装 # Vue 3 项目&#xff0c;安装最新版 Vant npm i vant# Vue 2 项目&#xff0c;安装 Vant 2 npm i vantlatest-v2 使用yarn安装或pnpm # 通过 yarn 安装 yarn add vant# 通过 pnpm 安装 pnpm add vant 在框架中引入即…