如何开发一个 Safari 插件

news2024/12/30 2:47:46

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) {
    // 查询所有 Tab
    browser.tabs.query({ active: true, currentWindow: true }, function (tabs) {
        // 获取当前正显示的 Tab
        var 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 中 img
                var 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.coloradmin.cn/o/1116592.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微软正式发布开源应用平台 Radius平台

“ 10 月 18 日&#xff0c;微软 Azure 孵化团队正式发布开源应用平台 Radius&#xff0c;该平台将应用程序置于每个开发阶段的中心&#xff0c;重新定义应用程序的构建、管理与理解方式。” 简单的概括就是&#xff0c;它和Kubernetes不一样&#xff0c;Radius将应用程序放在每…

DevExpress WPF Pivot Grid组件,可轻松实现多维数据分析!(二)

在上文中&#xff08;点击这里回顾>>&#xff09;我们主要为大家介绍了DevExpress WPF Pivot Grid组件的超快速枢轴分析功能、Microsoft分析服务等&#xff0c;本文将继续介绍图表透视数据的处理、MVVM支持等。欢迎持续关注我们&#xff0c;探索更多新功能哦~ P.S&#…

LNMP架构部署Discuz论坛系统

文章目录 LNMP架构&部署Discuz论坛系统部署LNMP架构环境前期准备安装Nginx安装mariadb安装php配置nginx 部署Discuz论坛系统下载Discuz论坛系统代码包部署Discuz论坛系统配置虚拟主机安装Discuz论坛访问站点尝试注册一个账号 LNMP架构&部署Discuz论坛系统 部署LNMP架构…

R语言:主成分分析PCA

文章目录 主成分分析处理步骤数据集code 主成分分析 主成分分析&#xff08;或称主分量分析&#xff0c;principal component analysis&#xff09;由皮尔逊&#xff08;Pearson,1901&#xff09;首先引入&#xff0c;后来被霍特林&#xff08;Hotelling,1933&#xff09;发展…

xtrabackup恢复数据时提示“This target seems to be not preared yet.”

测试MySQL数据库备份文件可用性。 备份文件是腾讯云平台备份的MySQL。文件需要xtrabackup恢复。 执行到xtrabackup --prepare --target-dir./mysql时&#xff0c;没有像往常开始执行命令而是给出了一个简短提示。 “This target seems to be not preared yet.” 为了确认前面…

软件工程与计算总结(二十二)软件开发过程模型

&#xff08;自顶向下&#xff0c;逐层细化&#xff09; 目录 一.软件开发的典型阶段 1.需求工程 2.软件设计 3.软件构造 4.软件测试 5.软件交付 6.软件维护 二.软件生命周期模型 三.软件过程模型 四.构建-修复模型 五.瀑布模型 六.增量迭代模型 七.演化模型 八…

Leetcode 第 361 场周赛题解

Leetcode 第 361 场周赛题解 Leetcode 第 361 场周赛题解题目1&#xff1a;2843. 统计对称整数的数目思路代码复杂度分析 题目2&#xff1a;生成特殊数字的最少操作思路代码复杂度分析 题目3&#xff1a;统计趣味子数组的数目思路代码复杂度分析 题目4&#xff1a;边权重均等查…

Git简洁安装方式和使用方式【附安装包资源,Git基础操作,如拉取项目、上传代码、拉取代码】

软件安装包 项目版本管理软件 Git windows版本安装包 安装步骤 双击按照包之后&#xff0c;直接next 安装位置尽量不要选择C盘&#xff0c;如果只有C盘&#xff0c;可以尝试分盘&#xff0c;如果C盘已经很小了&#xff0c;那就没办法了 选择完安装位置之后&#xff0c;直…

网络编程:事件模型关于epoll 边缘触发与水平触发的理解

文章目录 EPOLL事件有两种模型&#xff1a;ET模式LT模式运行区别边缘触发的实际使用代码如下 EPOLL事件有两种模型&#xff1a; Edge Triggered (ET) 边缘触发只有数据到来才触发&#xff0c;不管缓存区中是否还有数据。 Level Triggered (LT) 水平触发只要有数据都会触发。 (…

【USRP】软件无线电基础篇:长波、中波、短波

一、频率和波长 类型频率波长长波30&#xff5e;300千赫&#xff08;KHz&#xff09;10&#xff5e;1千米中波300&#xff5e;3000千赫&#xff08;KHz&#xff09;10&#xff5e;1百米短波3&#xff5e;30兆赫&#xff08;MHz&#xff09;100&#xff5e;10米 二、传输距离 …

SystemVerilog Assertions应用指南 Chapter 11.5SVA检验器的时序窗口

11.5SVA检验器的时序窗口 到目前为止,带延迟的例子使用的都是固定的正延迟。在下面几个例子中,我们将讨论几种不同的描述延迟的方法属性p12检查布尔表达式“a&&b”在任何给定的时钟上升沿为真。如果表达式为真,那么在接下去的1-~3周期内,信号“c”应该至少在一个时钟周…

蓝桥杯每日一题2023.10.20

题目描述 等差数列 - 蓝桥云课 (lanqiao.cn) 知识点&#xff1a; 排序找出最大公约数则为公差 项数: n (第n项值-首项) / 公差 1。 n (an-a1) / d1 #include<bits/stdc.h> using namespace std; typedef long long ll; const int N 2e5 10; int a[N], n; int gcd…

高复杂度,斐波那契数列

n大的时候&#xff0c;值会很大

java中的容器(集合),HashMap底层原理,ArrayList、LinkedList、Vector区别,hashMap加载因子0.75原因

一、java中的容器 集合主要分为Collection和Map两大接口&#xff1b;Collection集合的子接口有List、Set&#xff1b;List集合的实现类有ArrayList底层是数组、LinkedList底层是双向非循环列表、Vector&#xff1b;Set集合的实现类有HashSet、TreeSet&#xff1b;Map集合的实现…

IoT 物联网共享充电桩场景中设备资产定位和地理围栏开发实践

基于经纬度的设备资产定位和地理围栏在物联网场景中应用广泛 01 物联网 GEO 场景架构方案 首先&#xff0c;IoT 终端设备通过卫星定位模块获取当前经纬度&#xff1b;然后&#xff0c;将坐标信息实时上报到物联网平台&#xff1b;最后&#xff0c;存储到 Redis GEO 数据库中。 …

Golang实现逻辑编排解释引擎

作者&#xff1a;井卓 文章简介&#xff1a; 逻辑编排提供一站式集成平台&#xff0c;简化了在集成接口、应用和服务时&#xff0c;所涉及的业务逻辑和流程。本文会介绍如何通过ChatGPT学习Golang、以及表达式解释器的实现和Golang解析引擎的基本设计架构。 Golang实现逻辑编…

openHarmony UI开发

常用组件和布局方式 组件 ArkUI有丰富的内置组件&#xff0c;包括文本、按钮、图片、进度条、输入框、单选框、多选框等。和布局一样&#xff0c;我们也可以将基础组件组合起来&#xff0c;形成自定义组件。 按钮&#xff1a; Button(Ok, { type: ButtonType.Normal, stateEf…

Git 安装和基础命令、IDEA 基础操作

目录 总结命令&#xff1a;1、安装&#xff1a;1、安装2、配置环境变量&#xff1a; 2、Git操作&#xff1a;1、初始化&#xff1a;1、姓名邮箱&#xff1a;2、初始化仓库&#xff1a;3、工作区和暂存区分析 2、提交文件3、查看版本库状态4、安装小乌龟git不显示图标 5、查看提…

Redis常用配置详解

目录 一、Redis查看当前配置命令二、Redis基本配置三、RDB全量持久化配置&#xff08;默认开启&#xff09;四、AOF增量持久化配置五、Redis key过期监听配置六、Redis内存淘汰策略七、总结 一、Redis查看当前配置命令 # Redis查看当前全部配置信息 127.0.0.1:6379> CONFIG…

微信小程序之会议OA首页数据交互,会议状态,会议人数转换,会议室交互,WXS的使用

前言&#xff1a; 本篇博客使用结合了SpringMVC&#xff0c;mybatis&#xff0c;maven&#xff0c;小程序&#xff0c;如果不熟悉使用可以翻看我之前的博客&#xff0c;以便大家可以更好的学习&#xff01;&#xff01;&#xff01; 一&#xff0c;会议OA首页数据的后台交互 这…