この投稿では、HTMLでmacOSのオリジナルのスクリーンセーバを作れる方法を紹介します。
macOSのスクリーンセーバを作ってみたいけど、SwiftもObjective-Cも分からない、分かるのはHTMLやCSS、JavaScriptなどウェブ関連技術だけ、というウェブ系プログラマむけの解説です。
ちなみに僕は、この投稿で紹介する方法で、JavaScriptの人気ライブラリをひたすら紹介するスクリーンセーバを作りました:
JavaScriptの人気ライブラリを紹介しまくるスクリーンセーバが完成した😌
— suin❄️TypeScript入門書執筆中 (@suin) April 30, 2020
需要があれば公開するかも pic.twitter.com/tOnUhMIbh8
Swiftなどを知らなくても、CSSやJavaScriptでアニメーションを頑張れば、こういった動きのあるスクリーンセーバが作れるわけです。
スクリーンセーバをHTMLで作る手順
Xcodeで新規プロジェクトを作る
まず最初に、スクリーンセーバのプロジェクトの下準備をしていきます。
Xcodeを起動して、新規プロジェクトを作ります。
![Blank_Skitch_Document.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F567ffc29-7194-0e2a-0d53-fb0d211f4817.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c829a32de32d902743f33542649e2f15)
その際、「Screen Saver」のテンプレートを選びます:
![Screenshot_2020_04_29_13_45.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fd77c6c80-d11b-c831-ca51-d5eac1d3f79f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=62e637ee8e04dc43642c181a0734eb7e)
「Product Name」「Organization Name」「Organization Identifier」は適当に:
![Screenshot_2020_04_29_13_48.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F2e2072c3-f24e-9f1b-a89f-5bfe10f6a4d8.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=7d650336820c4d3d3db77b1953883a88)
Swiftの接着剤コードを準備する
macOSは標準でHTMLだけでスクリーンセーバが作れるわけではないので、HTMLをスクリーンセーバ上に描画するためのコードは、Swiftで書いておく必要があります。
ここでは、スクリーンセーバとHTMLの接着剤となるSwiftのコードを用意する手順を説明していきます。
まず、先程新規作成したプロジェクトから、不要なObjective-Cのファイルを消します:
![MyScreenSaverView_h.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F69067eaa-d3a6-b345-2053-2d7d8d3d7079.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=ef840d84475515f2e5856339450f889d)
代わりに、消したファイルと同じファイル名 + .swift
で空のファイルを作ります。「MyScreenSaver」を右クリックして「New File」をクリックします。
![Screen Shot 2020-05-01 at 15.56.17.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Faf08e030-7862-0a29-507d-d4b0642a3d78.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=c4b8d4130a57a84962cea1bfb2eaf34a)
ファイル形式は「Swift File」にします:
![Screenshot_2020_05_01_15_57.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fd069b401-9f8e-cdcd-1c19-eed802f997a9.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=0fd4afae526989af6eab2f57708b3f4f)
ファイル名は「MyScreenSaverView.swift」にします:
![Banners_and_Alerts.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fedc28953-7d73-a62e-5b82-2edc6730619f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=e7187dfca5664f78b838037b3bd59cf6)
作成時に↓と聞かれますが、「Don't Create」を選びます:
![Screenshot_2020_05_01_16_00.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F186a11be-1ff5-9fab-4dda-357f7a4f465d.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=b55fca02546cfddd1f57ecf7a205d1f0)
Swiftファイルが作成されたら、デフォルトで入っているコードは消し、下記コードをコピペして上書き保存します:
import ScreenSaver
import WebKit
class MyScreenSaverView: ScreenSaverView, WKNavigationDelegate {
private var webView: WKWebView!
convenience init() {
self.init(frame: .zero, isPreview: false)
}
override init!(frame: NSRect, isPreview: Bool) {
super.init(frame: frame, isPreview: isPreview)
setupWebView()
}
required public init?(coder: NSCoder) {
super.init(coder: coder)
setupWebView()
}
private func setupWebView() {
let webConfiguration = WKWebViewConfiguration()
// webkitがローカルファイルを参照できるようにする設定
webConfiguration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs")
// webViewをスクリーンの大きさに合わせる
webView = WKWebView(frame: NSRect(x: 0, y: 0, width: frame.width, height: frame.height), configuration: webConfiguration)
webView.navigationDelegate = self
// webViewの背景を透明にする
webView.setValue(false, forKey: "drawsBackground")
// スワイプでの戻る/進むを無効にする
webView.allowsBackForwardNavigationGestures = false
// ピンチで拡大/縮小できる機能を無効にする
webView.allowsMagnification = false
// ローカルのHTMLを読み込む
if let htmlPath = Bundle(for: type(of: self)).path(forResource: "html", ofType: nil) {
let htmlUrl = URL(fileURLWithPath: htmlPath, isDirectory: true)
let indexUrl = URL(fileURLWithPath: htmlPath + "/index.html", isDirectory: false)
webView.loadFileURL(indexUrl, allowingReadAccessTo: htmlUrl)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// ページが遷移したタイミングでwebViewをスクリーンセーバに表示する
self.addSubview(webView)
}
// マウスが動いたときにスクリーンセーバが解除されるようにする(その1)
override func hitTest(_ aPoint: NSPoint) -> NSView? {
self
}
// マウスが動いたときにスクリーンセーバが解除されるようにする(その2)
override var acceptsFirstResponder: Bool {
true
}
}
このSwiftコードが何をしているか簡単に説明すると、スクリーンセーバが起動したらWebView(埋め込み版のSafariのようなもの)を起動し、html/index.html
を読み込み、それをスクリーンセーバ上に表示するといった処理が書かれています。
Swift側の準備は以上です。
HTMLファイルを作る
次に、スクリーンセーバのグラフィックデザインを実装していく場所であるindex.html
を作っていきます。
まず、html
フォルダを作りたいので、「MyScreenSaver」フォルダを右クリックして「Add Files to "MyScreenSaver"」をクリックします:
![Screen Shot 2020-05-01 at 16.09.56.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fb0b25bc6-0f6d-a4c7-9436-dbe5eaad72bc.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=e1f31972b056a28aa7373cf5596659b6)
すると、Finderのダイアログが出てくるので、「New Folder」をクリックし、「html」フォルダを作ったら「Add」をクリックして閉じます。
![Screenshot_2020_05_01_16_11.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Ff5bda91d-6747-507b-ca50-8efc4c1134ed.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=cf25b6f75b0724bfb5f617d69226acec)
次に、index.htmlを作るために、htmlフォルダを右クリック、メニューから「New File」を選びます:
![Screen Shot 2020-05-01 at 16.13.26.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F5090709f-d591-9edd-5c7d-8d15f38436e2.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=f6878b6b98a8d37c71f18ced6caede85)
「File」というファイルが作られるので、「index.html」に名前を変えておきます。
index.htmlの中身は適当に何か書いておきます:
<style>
h1 {
color: black;
background: white;
font-size: 30vh;
animation: blink 1s step-end infinite;
}
@keyframes blink {
75% { opacity: 0.0; }
}
</style>
<h1>Hello World</h1>
以上でHTMLファイルの準備は完了です。
スクリーンセーバを実行できるように設定する
続いて、スクリーンセーバを実行するための設定をしていきます。
Xcodeのメニューバーにある「MyScreenSaver」をクリックするとメニューが出るので、そこから「Edit Scheme」を選びます:
![Screen Shot 2020-05-01 at 16.21.09.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F442224c2-cebc-581e-76c6-6049e6c3f6f6.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=46a84ab81c23e51e25c5c1d3be1bb916)
「Run」の「Info」タブの「Executable」セレクトメニューから「Other」を選び、ScreenSaverEngine.appに設定します:
![Screenshot_2020_05_01_16_25.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fa8a68ff1-5fb9-ade4-d4d1-ab9a5b80c589.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=84dc193168876e3e93563c5186bc5f8e)
ScreenSaverEngine.appは/System/Library/CoreServices/ScreenSaverEngine.app
にあります。macOSのバージョンによって、ありかが異なる場合があります。
次に、「Arguments」タブを開き、
-window
-module "$(EXECUTABLE_NAME)"
の引数設定を追加します:
![Screenshot_2020_05_01_16_27.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fd384f597-db92-d4fa-5cfa-bbd18e84224f.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=23cd2ef00efec9ec5b40650a273291e0)
更に、実行ごとにスクリーンセーバを自動的にインストールするように設定します:
![Screen_Shot_2020-05-01_at_16_39_12.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F9c71250d-b88e-f971-f58d-6732a2a9265b.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=ff8bcbfd82d397bb3d1d57fbce90b01e)
open -W "${CODESIGNING_FOLDER_PATH}"
以上で、スクリーンセーバを実行するための設定は完了です。
スクリーンセーバを実行してみる
準備が整ったので、スクリーンセーバを実行してみましょう。
スクリーンセーバを実行するには、Command+Rを押すか、XcodeのRunボタン(▶アイコン)を押します。
実行が開始すると、設定アプリが立ち上がり、スクリーンセーバをインストールするか聞かれるので「Install」を選択します:
![Screen Shot 2020-05-01 at 16.46.30.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fb09830da-4dde-fe8f-45f0-2ff7844e43b7.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=14121a33f37bca554e047a0b444f3038)
すると、スクリーンセーバがインストールされ、スクリーンセーバの選択画面にプレビューが表示されるようになります。
![Screen Shot 2020-05-01 at 16.47.23.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F8431c005-fd6f-d9e1-8cca-66b578bc5728.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=6b3d673355abd975850059763873a576)
この状態で、設定アプリを閉じると、今度はスクリーンセーバを確認するためのウィンドウが表示されます:
![saver_window.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F055d4172-e603-c0c3-bf03-8c2f95dd8272.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=1e9705015835a802e0970012f4777439)
index.htmlに書いた内容が表示されるはずです。
あとは、index.htmlを作り込んでいくと、オリジナルのスクリーンセーバが作れます。
ちなみに、実行したときに、インストールされたスクリーンセーバは、実行が終了しても残るので、設定アプリで自分が作ったスクリーンセーバを選択しておけば、Xcodeを閉じてもそのスクリーンセーバが使われるようになります。
Safariを使った動作確認がおすすめ
HTMLを直してはXcodeの「Run」でスクリーンセーバをインストールし直して確認する、というのは開発体験としてかったるいので、HTML側にごりごり書いていくときはSafariで動作確認するのをおすすめします。Safariを使うと、ウェブインスペクタも使えるのでデバッグがはかどります。
ChromeやFirefoxではなくSafariを使う理由は、Swiftのコードで使っているWKWebView
が他ブラウザの環境よりSafariに近いからです。
普段、Swiftを書かない人は、Xcodeも慣れていないと思うので、HTMLをいじるときはVSCodeなど自分の好きなエディタを使ってもいいです。
Safariで動作確認するときは、html/index.html
を開くだけです。HTMLを直したら、リロードする。普段のウェブアプリの開発と同じ要領です。
スクリーンセーバの作りにもよりますが、fetch()
などで外部APIを叩いたりするときは、Same Origin Policyにひっかかってしまうことがあります。その場合は、Safariの「Devloper」→「Disable Cross-Origin Restrictions」をオンにしておくと良いです:
![Screen Shot 2020-05-01 at 16.56.30.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2Fa9736b92-733f-086d-fa4f-ca31c212f860.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=a85f2707d155a006519065500b232e8b)
また、フルスクリーンでの動作確認をするときは、「View」→「Always Show Toolbar in Full Screen」のチェックを外しておくと良いです:
![Screen Shot 2020-05-01 at 16.59.46.png](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F889%2F06d7bffe-d18d-2472-f786-a4a280fea4b8.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=01780c270d91898d5b6a76a5961c0738)
おわり
macOSのスクリーンセーバを作るのに、Swiftの知識はほぼ不要です。
慣れ親しんだHTMLやJavaScriptを駆使して、自分だけのスクリーンセーバを作ってみてはいかがでしょうか。
最後までお読みくださりありがとうございました。Twitterでは、Qiitaに書かない技術ネタなどもツイートしているので、よかったらフォローしてもらえると嬉しいです→Twitter@suin