20190915のiOSに関する記事は6件です。

Unity+ARKit3のbody segmentation結果を配列として取得する

既知の問題(2019/9/16更新)

以下の方法は、セグメンテーションのテクスチャに限り、端末の向きを変更するとそれ以降値が変化しなくなる問題が起きています。(デプスのテクスチャは問題なし。Orientation設定は関係なし)
そのため、あまり上手い方法ではないかもしれませんので、そのつもりで利用してください。

やりたいこと

ARKit3を利用することで人物領域をセグメンテーションすることができる。
しかし、結果がTexture2Dとして取得されるので、そのままでは結果を加工しにくい。
なので、byteなどの配列として結果を取得したい。

ハマったポイント

Texure2Dなので、GetPixels()などを使えば一瞬だと思ったが、関数がうまく機能しないらしい。

原因(推定)

UnityのARKit3プラグインを確認していくと、このTexture2Dはネイティブで作られている模様。(CreateExternalTexture/UpdateExternalTextureでの作成・更新処理を発見)
Texure2Dはネイティブで作られたものをラップしているだけなので、GetPixels()などの関数が正しく機能しなかったと思われる。
参考(テラシュールブログさん):
http://tsubakit1.hateblo.jp/entry/20140104/1388830289
http://tsubakit1.hateblo.jp/category/トラブルシューティング?page=1469026740#RenderTextureをTexture2Dに流し込む

解決策

凹みTipsさんの
Low-Level Native Plugin Interface を利用してネイティブから Unity のテクスチャを高速に更新する方法を調べてみた - 凹みTips
によると、iOSにおいてはid<MTLTexture>がテクスチャの実体らしいので、以下のようなプラグインを書いて、配列として取得することで解決。
idから配列としてデータを取得する関数は以下。
https://developer.apple.com/documentation/metal/mtltexture/1516318-getbytes

/Assets/Plugins/iOS/TextureExtention.mm
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>

extern "C" {
    void GetNativePixels(id<MTLTexture> texture, int width, int height, int sizePerRow, char *buffer) ;
}

void GetNativePixels(id<MTLTexture> texture, int width, int height, int sizePerRow, char *buffer) {
    [texture getBytes:buffer bytesPerRow:sizePerRow fromRegion:MTLRegionMake2D(0, 0, width, height) mipmapLevel:0];
}
/Assets/Plugins/TextureExtention.cs
using System;
using UnityEngine;
using System.Runtime.InteropServices;

public class TextureExtention { 
    [DllImport("__Internal")]
    public static extern void GetNativePixels(IntPtr texturePtr, int width, int height, int sizePerRow, [Out] byte[] buffer);

    public static void GetNativePixels(Texture2D humanTexture, ref byte[] buffer) {
        // humanTexture は ARKit3で取得されたセグメンテーション結果が格納されたテクスチャ
        IntPtr humanTexturePtr = humanTexture.GetNativeTexturePtr();
        int width = humanTexture.width;
        int height = humanTexture.height;
        int sizeParRow = humanTexture.width * 1; // ボディセグメンテーションではテクスチャフォーマットはR8なので 1ピクセル=1Byte
        GetNativePixels(humanTexturePtr, width, height, sizeParRow, buffer);
    }
}

補足

今回ネイティブプラグインを作って対処しましたが、Unity内でRenderTexture->Texuture2Dへの変換のようにテクスチャを本当のTexutre2Dコピーして、GetPixels()を使う方法でもできるかもしれません。
また、セグメンテーション結果ではなくデプス推定結果でも同じようにすれば大丈夫です。その際はテクスチャフォーマットがRFloatなので、その調整をする必要があります。

動作環境

Unity 2019.2.5f
Xcode 11 GM Seed

感想

GetPixels()が使えないという判断までも時間がかかったし、初めてのiOSネイティブプラグイン作成だったので色々苦労してしまいました…。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iPadのOSアップデートをブロックする方法ないの?

組織のiPadを管理している人を恐怖のどん底に追い落とすような、恐ろしい情報が‥。

iPad 上の iOS13 の挙動変更により Azure AD 条件付きアクセス ポリシーの動作に影響が生じる

Appleの仕様変更で、iPadを13にバージョンアップすると、Safariとかネイティブメーラーは、MacOSとみなすぜ!なので準備してね!ということらしい。

そうなっちゃうと、認証とセキュリティポリシーが影響受けそう。下手すればログインできなくなるとか、セキュリティポリシーの適用外になりかねない。

認証の構成やセキュリティポリシーの適用から、iPadのOSバージョンを12にとどめておきたい。せめて無期限とは言わなくても、検証する間だけでもいいから、ってことで調べてみた。

ざっくり

Intuneだとこの記事が一番わかりやすい。
Microsoft Intuneで iOS のアップデートを制限する

設定手順の紹介もあるけど、こういうことらしい。
・iOS11.3移行
・監視対象デバイス
・OSのバージョンがリリースされて最長90日までは制限できる
・完全にブロックではなく、あくまで延期でしかない

公式ドキュメント

いくつかひろってみた。

■Apple 管理対象のソフトウェアアップデートについて

iOS 11.3 以降、tvOS 12.2 以降では、MDM の管理者が、監視対象のデバイスに新しいソフトウェアアップデートが表示される時期を遅らせることができます。

iOS や macOS のソフトウェアアップデートを管理者が遅らせている場合は、管理者によって認められた最新のソフトウェアアップデートがデバイスで実行されているというメッセージが表示されます。

■Intune Intune に iOS ソフトウェア更新プログラム ポリシーを追加する

ソフトウェアの更新ポリシーにより、監視対象の iOS デバイスに利用可能な最新の OS 更新プログラムを強制的に自動インストールします。 ポリシーを構成しているときに、デバイスで更新プログラムをインストールしない日時を追加できます。
この機能は、以下に適用されます。
iOS 10.3 以降 (監督下)
デバイスは約 8 時間ごとに Intune でチェックインされます。 更新プログラムを利用できて、制限時間中ではない場合、デバイスで最新の OS 更新プログラムをダウンロードしてインストールします。 デバイスを更新するために必要なユーザーの操作はありません。 ポリシーにより、ユーザーが手動で OS を更新できなくなることはありません。

10.3ってあるのは誤記?

■AirWatch iOS デバイス用の制限事項プロファイルの構成

このオプションを有効にし、ソフトウェアの更新を延期する日数を指定します。日数は 1 ~ 90 日の範囲です。(iOS 11.3 以降の監視モード デバイス)。日数は、ソフトウェアの更新がリリースされてからの期間です。プロファイルをインストールしてからの期間ではありません。

荒っぽい方法

アップデート用のサーバーへのアクセスを、常時VPN構成+firewallでブロックという方法もあるらしい。

iOS バージョンアップを止める方法
※2014年の記事のようです。

まとめ

外部認証サービス使ってたら、そっちの影響も考えなきゃいけない。
とりあえず、β版のiPad用意して検証&
ユーザーのデバイスは延期してその間に検証&対策検討、ですかね・・・。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

R.swift5.0でZeplinとの色の連携が完璧になった

R.swift5.0でZeplinについてのtipsです。

R.swift5.0未満のつらみ

R.swiftがCLRファイル形式しかサポートしていなかったので、せっかくZeplinがAsset Colorsを吐き出してくれるのに、R.colorが使えない...。(このCLRファイルが絶妙に使いにくいのです)

なのでZeplinで吐き出される自動生成のコードをXcodeのプロジェクトに追加して利用していました。この問題点は、デザインスペックの管理はZeplin、ソースコード上でのリソース管理はR.swiftに分離したいのに、一部ソースコード上でのリソース管理をZeplinが行なってしまうことです。

この下側のような自動生成コードを使っていました。

R.swift5.0以降の嬉しさ

R.swift5.0のリリースノートの一文に

Removed CLR file support, use color resources instead

CLRファイルのサポートを取り除いて、代わりにカラーリソースを使うようにしましたと書いてあります。

これによって、R.swift5.0からはColor Assetsを参照できるようになったので、自動生成のコードを利用しなくても問題なくなり以下のようなフローに改善されました。

  1. Zeplinの「export to xcassets」を押す
  2. ビルドをかける

  3. R.colorで色を参照可能になる

超楽!何もしなくて良い!

これによって、色に関してはデザインスペック管理はZeplin、リソース管理はR.swiftという分離を図ることができました。

要望

これはXcode側の問題なのですが、fontをxcassetで定義してコードとストーリーボードから参照できるようになれば、Zeplinがxcassetにfont吐き出して、R.swiftがそれをR.fontで使えるようにして...。ってなりそうなので良いなーと思っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RxSwiftをCarthageで入れて起動時に`Library not loaded`エラーが出たらRxRelayも追加して解決した

RxSwiftとRxCocoaを追加後、ビルドはサクセスするのですが、実機で動作確認ししようとすると以下のエラーで落ちてしまいました。

dyld: Library not loaded: @rpath/RxRelay.framework/RxRelay
  Referenced from: /var/containers/Bundle/Application/xxxxxxx-xxxx-xxxx-xxxx-477EBE5CC202/xxx.app/xxx
  Reason: image not found

今回の解決方法は、RxRelayも追加することでした。

RxSwiftライブラリをビルドすると、以下の5つのフレームワークが生成されます。

  • RxSwift
  • RxCocoa
  • RxRelay
  • RxBlocking
  • RxTest

RxSwift, RxCocoaのみXcodeで追加すれば良いと思っていたのですが、どうやらRxRelayも必要みたいですね?

TARGETS -> General -> LinkedFrameworks and Libraries にRxRelayも追加し、
Build Phases の Input Files Lists, Output Files Lists にも追記しました。

input.xcfilelist
$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework
$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework
$(SRCROOT)/Carthage/Build/iOS/RxRelay.framework
output.xcfilelist
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxSwift.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxCocoa.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxRelay.framework

以上で、無事に実機での動作確認を行えるようになりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RxSwiftをCarthageで入れたら実機で起動できなかったので、RxRelayも追加して解決した

RxSwiftとRxCocoaを追加後、ビルドはサクセスするのですが、実機で動作確認ししようとすると以下のエラーで落ちてしまいました。

dyld: Library not loaded: @rpath/RxRelay.framework/RxRelay
  Referenced from: /var/containers/Bundle/Application/xxxxxxx-xxxx-xxxx-xxxx-477EBE5CC202/xxx.app/xxx
  Reason: image not found

今回の解決方法は、RxRelayも追加することでした。

RxSwiftライブラリをビルドすると、以下の5つのフレームワークが生成されます。

  • RxSwift
  • RxCocoa
  • RxRelay
  • RxBlocking
  • RxTest

RxSwift, RxCocoaのみXcodeで追加すれば良いと思っていたのですが、どうやらRxRelayも必要みたいですね?

TARGETS -> General -> LinkedFrameworks and Libraries にRxRelayも追加し、
Build Phases の Input Files Lists, Output Files Lists にも追記しました。

input.xcfilelist
$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework
$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework
$(SRCROOT)/Carthage/Build/iOS/RxRelay.framework
output.xcfilelist
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxSwift.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxCocoa.framework
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/RxRelay.framework

以上で、無事に実機での動作確認を行えるようになりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今回、アプリ内でQRコードを生成して表示する必要があったのでRSBarcodesを使いました

バーコード生成用クラスを作成

import AVFoundation
import UIKit
import RSBarcodes

/// バーコードを生成する
final class BarcodeGenerator {

    /// 生成予定のコードを検証する
    func validateCode(_ code: String, codeObjectType: AVMetadataObject.ObjectType) -> Bool {

        return RSUnifiedCodeValidator.shared.isValid(
            code,
            machineReadableCodeObjectType: codeObjectType.rawValue
        )
    }
    /// コードを生成する
    func generateCodeImage(_ code: String, codeObjectType: AVMetadataObject.ObjectType) -> UIImage? {

        return RSUnifiedCodeGenerator.shared.generateCode(
            code,
            machineReadableCodeObjectType: codeObjectType.rawValue
        )
    }
    /// スケールを使ってリサイズする
    func resizeCodeImage(_ image: UIImage, scale: CGFloat) -> UIImage? {

        return RSAbstractCodeGenerator.resizeImage(image,
                                                   scale: scale)
    }
    /// サイズを指定してリサイズする
    func resizeCodeImage(_ image: UIImage, size: CGSize, contentMode: UIView.ContentMode) -> UIImage? {

        return RSAbstractCodeGenerator.resizeImage(image,
                                                   targetSize: size,
                                                   contentMode: contentMode)
    }
}

専用のクラスを用意して、ライブラリが持つ機能をメソッド化しました。
import AVFoundationは必須です。

QRコードを生成する場合は、codeObjectType: AVMetadataObject.ObjectType.qrと指定します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む