Hatena::ブログ(Diary)

hishidaのblog このページをアンテナに追加 RSSフィード

プロフィール

hishida

hishida

EB series support page 管理人 ブログ

2018-02-25

[][][]EBWin4 64bit版

要望を頂いている訳ではないが、EBWin4の64bit版を実験的にビルドしてみた。

WindowsクライアントOSではVistaから64bit版が提供されるようになり、現在ではインストールベースで64bitが32bit版を上回っている。32bitOSでは物理メモリが3GBが上限だが、64bitなら物理メモリの上限まで使用できる。

ちなみにmac OSもHigh Sheirraが32bitアプリが動作する最後のOSと告知されており、iOSもiOS11から32bitはもはや実行できない。Windowsアプリもいずれは64bit対応が必須になるだろう。

EBMacやEBPocketはすでに64bit化が済んでおり、EBWin4もそろそろ64bitネイティブ化する時期だと思う。

Visual Studio で64bitアプリを作成する

既存の32bitアプリを64bit化する手順は、

本当に64bitで動いているかどうかは、タスクマネージャで確認できる。

1日くらいの作業で64bit化できたが、私の通常の使用環境だと32bitとの違いは全然感じない。数十個の辞書をグループ化して検索するような極端なケースでは、多少恩恵があるかもしれない。

次の目標はEBStudio2の64bit化になるが、これは4GB超の巨大辞書を作るときに必要になると思う。

P.S.

EBStudio2の64bit版も2/27にリリースしました。特に問題はないように見えます。

2018-02-01

[][] iPhoneX 全画面対応

iPhone Xが発売されて数カ月が立つが、iPhone Xはこれまでと違う独特のアスペクトレシオを持ち、アプリもそれなりの対応が必要になる。

当方の開発環境はこれまでMac OS X 10.11 El Capitan および Xcode 8だったが、iPhone Xの対応はXcode 9以降となる。さらにXcode9の動作環境はmacos X Sierra以降なので、iPhone Xエミュレータを試すには開発環境をアップグレードしないといけない。

開発環境を更新するのはリスキーなので、VMWare Fusionmacos X Sierra環境を作り、その上でXcode9のiPhone Xエミュレータを動かしてEBPocket for iOSの動作確認を行い、対応できたものと思って安心していた。(→ iPhone X の解像度の問題 - hishidaのblog

ところがiPhone Xの実機で全画面で動作させるには、Xcode9でビルドおよび提出が必要であり、Xcode8以前でビルドしたアプリiPhone Xで実行すると上下に黒い枠が表示されることがわかった。

いずれはXcode9以上でないとアプリの提出が認められなくなるので、重い腰を上げてXcode9対応を行うことにした。

1.まずMac OS Xを 10.11 El Capitanから10.12 macos X Sierraアップグレードする。これ自体は特に問題は無い。

2.次にXcode9.2をインストールし、Xcode8時代のプロジェクトをコンパイルしてみると、早速コンパイルエラーの山となった。

Command /usr/bin/codesign failed with exit code 1

Code signing fails with error 'resource fork, Finder information, or similar detritus not allowed'

Technical Q&A QA1940: Code signing fails with error ’resource fork, Finder information, or similar detritus not allowed’

上のURLに書かれているように、次のコマンドを実行することで解決

xattr -cr プロジェクトディレクトリ

3.これで大丈夫と思いきや、iOS11で実行するとUIScrollViewのcontentInsetがずれるという凶悪な問題が発生。

no title

上記URLとは違う解決方法だが、結局、次の方法でiOS11のcontentInsetの自動調整を抑止し、さらに表示位置をiOSのバージョン毎に調整することで解決

MainWindow.xibのRootViewControllerで下記設定を行なう

Adjust Scroll View Insets : チェックを外す ←勝手なcontentInsetの自動調整を止める

Under Top Bars : チェックをつける←NavigationBarの高さが変わっても潜り込まずにbarの下に表示される

iOS6からiOS7になるときにもNavigationController Barの下にUITableViewが潜り込むという問題が起きたが、その時の対処が不完全であったことが、iOS11になって表面化したらしい。

no title

ただ今回のやり方が合っているのかどうかはわからない。そのうち「おまえらのiOS11対応は間違っている」と言われるかもしれない。

一時はもうAppStoreに提出できないのではないかと思って悩んだが、最終的には無事Xcode9でiPhone X対応版を提出することができた。

f:id:hishida:20180209081515p:image

一つの問題点として、Xcode9でビルドすると、TargetOSの下限がiOS8になってしまう。ただしiOSは大多数のユーザが最新のOSに速やかにバージョンアップするので、実際は問題は無いだろう。

iOSはメジャーバージョンアップごとに破壊的修正が入るので、開発者にとっては大変である。

2018-01-07

[][] iPhone X の解像度の問題

「EBPocket が iPhone Xに対応していない」というご意見を頂いたので、Xcode 9 のエミュレータで確認したところ、横画面のときに検索一致リストと本文の横幅がイビツになっていることがわかった。次のスクリーンショットのように、本文の方が幅が狭くなっている。本当は横位置の時は本文の幅を広く取りたい。

f:id:hishida:20180107233012p:image

これはiPhone X だけアスペクトレシオが2:1と縦長であることが原因だ。

デバイス名画面サイズ画面解像度アスペクト
iPhone X5.8 inch2436 x 11252:1
iPhone 8 Plus/ 7 Plus/ 6s Plus/ 6 Plus/ 5.5 inch1920 x 108016:9
iPhone 8 / 7 /6s / 64.7 inch1334 x 75016:9
iPhone5/5S/5c/SE4.0 inch1136 x 64016:9
iPhone4/4S3.5 inch960 x 6403:2
iPhone3G/3GS3.5 inch480 x 3203:2

これまでは短辺側の幅が必ず本文の幅だったが、iPhoneXだと横位置の時は、検索一致リスト側を短辺の幅にしないといけない。修正後はこんな感じ。

f:id:hishida:20180107233006p:image

エミュレータでしか検証していないので不安だが、とりあえず修正版を提出してみた。

P.S.

当方の開発環境は未だにOS X El CapitanおよびXcode8だが、どうやらXcode8でビルドして提出すると、iPhone X の全画面にならず、上下に黒い領域が表示されるらしい。Xcode9 はmacOS Sierra以上の対応なので、Xcode9 で本番用のプログラムをビルドして提出するには、メインのMacbook proをmacOS Sierraか High Sierra にアップデートし、Xcode9をインストールしなければならない。環境を完全にバックアップする必要もあるので、たぶん1日がかりの仕事になる。対応にはまだしばらく時間がかかる模様。

2017-07-04

[][] EBPocket for Android pro Text-to-speech サポート

Text-to-speechはテキストの読み上げ機能で、Androidでは1.6から早くもAPIが提供されていた。だがAndroidの標準のテキスト読み上げエンジンは、英語、イタリア語、スペイン語、ドイツ語、フランス語しかサポートしておらず、日本語の読み上げを行うためにはサードパーティの日本語読み上げエンジンを導入する必要があった。このため、EBPocketも読書尚友も、Text-to-speechをサポートしてこなかった。

ところが、昨年購入したASUS Zenfone 3 laserは、標準で日本語読み上げエンジンを搭載していることがわかり、Text-to-speechをサポートする意欲が湧いてきた。

とりあえずEBPocket for Android proで対応してみた。

  • テキストの範囲を選択してコンテキストメニューでTTSを選択すると、範囲指定したテキストを読み上げる
  • 範囲指定せずにメニューからTTSを選択すると、本文全てを読み上げる
  • 画面にタッチすると読み上げを止める
  • 文字列中にCJK統合漢字、ひらがな、カタカナを含んでいた場合は、日本語読み上げエンジンを使う。含まれていない場合は英語の読み上げエンジンを使う。
  • CJK統合漢字に使用する読み上げエンジンは、日本語と中国語から選択できる。

日本語読み上げエンジンが使えない機種でも、少なくとも英語の読み上げはできるので、英和や和英で発音を確かめたい場合には、それなりに有用だと思う。

次は当然、読書尚友でサポートしなければいけないと思っている。

2017-06-19

[] EBPocket for iOS のApp Extension対応について

iOSアプリケーション間でテキストを受け渡したい場合、以前はURL Scheme、クリップボード、OpenInぐらいしか方法がなかった。

iOS8からは App Extension という新たなアプリケーション連携の方法が提供されており、Androidのintentのように、任意のアプリケーション間でテキストやイメージが受け渡せるようになった。

iOS8の登場からもう3年も経っているが、遅ればせながらEBPocket Pro for iOSにもApp Extensionを実装してみた。

App Extensionには種類があるが、EBPocketではShare Extensionに対応した。

共有の画面例

Safariやメモで文字列を範囲選択し、[共有...]を実行すると、App Extensionに対応したアプリの一覧が表示される。

f:id:hishida:20170619100117p:image

f:id:hishida:20170619100211p:image

ここでEBPocketを選択し、Postを押すとEBPoketが起動して受け渡された文字列で検索を実行する。

f:id:hishida:20170619100302p:image

f:id:hishida:20170619100330p:image

左上の戻るボタンを押すと呼び出し元のアプリに戻る。

スプリットビューが使用できるiPadでは、SafariとEBPocketを両方開いたままにして、Safariで文字選択した文字列でEBPocketで検索できる。

f:id:hishida:20170619100453p:image

f:id:hishida:20170619100444p:image

実装の方法

App Extensionのプログラミングについては、Appleから日本語訳が出ている.

App Extensionプログラミングガイド:App Extensionはアプリケーションの効用を拡大する

App Extensionは単独で配布することはできず、必ず収容アプリと同時に配布しないといけない。今回はEBPocketが収容アプリということになる。

App Exensionと収容アプリとは別のバイナリであり、開発言語が異なっていてもいい。今回は勉強のため、Swift3で書くことにした。

ただし、実行できるiOSのバージョンの条件がiOS7.0以上になったが、現在では困る人はほとんどいないと思う。

Xcodeで 既存のアプリにApp Extensionを追加するのは簡単で、

[File]->[New]->[Target...]を押してApp Extensionの種類からShare Extensionを選択し、Product Nameを入力する。

収容アプリの Bundle Identifire にProduct Nameを連結したものが、App ExtensionのBundle Identifireになる。

収容アプリのBundle Identifire : 
        info.ebstudio.EBPocketPro
App ExtensionのBundle Identifire : 
        info.ebstudio.EBPocketPro.shareExtension

ここで次の3つのファイルが生成されるので、これを雛形としてコードを追加していく。

  • ShareViewController.swift
  • Maininterface.storyboard
  • info.plist

info.plistでは:

  1. Bundle display name にextensionの表示名を設定(この場合EBPocket)
  2. 共有でテキストのみ選択できるようにNSExtensionActivationRuleを修正する
    NSExtension
        NSExtensionAttributes
            NSExtensionActivationRule
                NSExtensionActivationSupportsText	Boolean	YES

収容アプリと同じアイコンを使用するには、Targetに収容アプリの .xcassets のアイコン名を設定する:

Build Phases
    Copy Bundle Resources
        + 収容アプリの .xcassets   を追加する
Build Settings
    Asset Catalog App Icon Set Name     ->  AppIcon (.xcassetsのアイコン名)

ここで一つ困ったことは、Share Extension から収容アプリを起動する方法が URL Scheme しかないのだが、公式の方法である openURL:completionHandler: を実行できるExtensionの種類がToday Extensionだけという問題である。

これは世界中でみんな困っていて、ネットで検索するとさまざまな回避方法が出ている。

最終的に、iOS10でも実行できるSwift3の最終的なソースは次のようになった。

//
//  ShareViewController.swift
//  shareExtension
//
//  Created by hishida on 2017/06/14.
//
//

import UIKit
import Social

class ShareViewController: SLComposeServiceViewController {
    
    override func isContentValid() -> Bool {
        // Do validation of contentText and/or NSExtensionContext attachments here

        let canPost: Bool = self.contentText.characters.count > 0
        if canPost {
            return true
        }
        
        return false
    }

    override func didSelectPost() {
        // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
        
        let inputItem: NSExtensionItem = self.extensionContext?.inputItems[0] as! NSExtensionItem
        let itemProvider = inputItem.attachments![0] as! NSItemProvider
        
        if (itemProvider.hasItemConformingToTypeIdentifier("public.plain-text")) {
            itemProvider.loadItem(forTypeIdentifier: "public.plain-text", options: nil, completionHandler: {
                (item, error) in
                
                let URLSCHEME:String = "ebpocket://search?text="

                let encodedString:String = self.contentText.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!
                
                let myUrlStr:String = URLSCHEME + encodedString

                let url = NSURL( string:myUrlStr )
                let context = NSExtensionContext()
                context.open(url! as URL, completionHandler: nil)
                
                var responder = self as UIResponder?
                
                while (responder != nil){
                    if responder?.responds(to: Selector("openURL:")) == true{
                        responder?.perform(Selector("openURL:"), with: url)
                    }
                    responder = responder!.next
                }
                
            })
        }

        // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
        self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
    }

    override func configurationItems() -> [Any]! {
        // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
        return []
    }

}

開発作業以上に手間取ったのが、App Storeに提出するための証明書の問題だった。

わかってみるとなんでもないが、App Extensionと本体の収容アプリは別のバイナリのため、Application Identifier、Provisioning profileは全て収容アプリとは別にする必要がある。

  1. iOS Dev Centerで Extension用の Application IdentifierとProvisioning profileを作成する
  2. 収容アプリのEntitlements.plistとは別に、App Extension用のEntitlements.plistを作成し、ここでApp ExtensionのApplication Identifierを定義する

ちなみApplication Identifierとは、開発者を表す10桁のprefix + Bundle Identifierのこと:

 XXXXXXXXXX.info.ebstudio.EBPocketPro.shareExtension 

あと、収容アプリと App Extensionのバージョン番号が食い違っていると提出時にワーニングが出るが、これは無視していいらしい。