objc_util — オブジェクティブC の APIs との橋渡しのユーティリティー

 objc_util モジュールは、Python からオブジェクティブC の API(Application Programming Interface:プログラムから iOS にアクセスするためのインターフェイス)群への「橋渡し」をします。

 (訳注 この項目については、私自身のオブジェクト指向の理解が不十分であることと、原文も少々乱れ気味であること、サンプルのスクリプトも動作が確認できていないことから、適切な訳になっていない可能性があります。お読みになる際には、是非、原文も併せてご確認をお願いします。)

 C言語と互換性のあるデータタイプを持つ python の関数ライブラリーである ctypes と、オブジェクティブCのランタイムライブラリーをベースに成り立っており、objc_util を使用することによって、既存のオブジェクティブCのクラスを Python から扱えるようになります。この時、Python のメソッド呼び出しをオブジェクティブCのメッセージに自動的に変換するような方法が用いられます。

  簡単な例として、次のオブジェクティブCのコードは、

UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]
[pasteboard setString:@"Hello Objective-C"];

 以下の Python のコードに翻訳することができます:

from objc_util import *
UIPasteboard = ObjCClass('UIPasteboard')

pasteboard = UIPasteboard.generalPasteboard()
pasteboard.setString_('Hello Objective-C')

 (訳注 上記のスクリプトを実行しただけでは、一見、何も起こらないように見えますが、クリップボードに'Hello Objective-C'という文字列を書き込んでいます。スクリプト実行後、例えば python のエディター内の画面の任意の場所をタップして「ペースト」すると、スクリプトが実際に実行されたことが分かります。)

 Python からオブジェクティブCのAPI を呼び出す際に、オブジェクティブCで直接コードを書くのに比べて極端に多量のコードを書く必要がないことが分かります。

 このスクリプトの実行にあたり、objc_util は、Python の関数呼出しをオブジェクティブCのメッセージに変換するため、objc_msgSned() などの適切な関数呼出しを行います。また、Python の一般的な型(例えば、上記のスクリプトでの文字列だけでなく、リストやディクショナリーも)については、このメソッドを呼び出すことによって、オブジェクティブCの同等の基本的な型(NSString, NSMutableArray, NSMutableDictionary など)に変換されます。

 オブジェクティブ Cのセレクター(メソッドの内部表現)から Python のメソッドの名前への変換は、極めて単純に行えます。基本的にはコロン「:」をアンダースコア「_」に置き換えるだけです。例えば、doFoo:withBar: というセレクターは、doFoo_withBar_ というメソッドになります。(注 末尾にもアンダースコアがつくことにご注意ください)

 多くの場合、もう少し「パイソンぽい」文法を使うこともできます。例えば、オブジェクティブCのセレクター名の一部としてのキーワードとなる引数を使って:

# From: UIColor *color = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0]
# ...to:
UIColor = ObjCClass('UIColor')
color = UIColor.colorWithRed(1.0, green=0.0, blue=0.0, alpha=1.0)
# or even:
color = UIColor.color(red=1.0, green=0.0, blue=0.0, alpha=1.0)

 この、より自然な文法は多くの場合動作しますが、メソッド名とキーワードとなる引数の組合せによっては、オブジェクティブCのメソッド呼出しに適切に変換できない場合があります。このような場合、キーワードとなる引数を使わずに、前述のようにコロンをアンダースコアに置き換える方法で呼出し変数を記述してください。

 (注 ctypes モジュールの使用により Python がクラッシュすることがあります。オブジェクティブCのメソッドを呼び出す場合には、正しいパラメーター型を選ぶよう慎重に行ってください。)

例 1 – 画面の明るさを設定する

 この単純な例は、デバイスの画面の明るさを設定するものです:(訳注 このスクリプトは現在のところ動作が確認できていません)

from objc_util import *

# 'Import' an Objective-C class (generate a proxy for the class):
UIScreen = ObjCClass('UIScreen')

# Call a class method, this is equivalent to `[UIScreen mainScreen]` in Objective-C:
screen = UIScreen.mainScreen()

# `screen` is now an ObjCInstance that wraps an Objective-C object, and forwards messages to it.

# The following call is equivalent to `[screen setBrightness:0.6]`:
screen.setBrightness(0.6)

例 2 – Music/iPod アプリの現在の曲にアクセスする

 このコードは、現在再生中の曲のアーティスト名と曲名をコンソールに表示します。(注 純正の Music アプリにのみ対応しており、サードパーティ製の音楽再生アプリでは使用できません)(訳注 このスクリプトは現在のところ動作が確認できていません)

from objc_util import *

MPMusicPlayerController = ObjCClass('MPMusicPlayerController')
player = MPMusicPlayerController.systemMusicPlayer()
now_playing = player.nowPlayingItem()
if now_playing:
    artist = now_playing.valueForProperty_('artist')
    title = now_playing.valueForProperty_('title')
    print('Now playing: %s -- %s' % (artist, title))
else:
    print('No music playing')
Creating New Objective-C Classes

 より高度なオブジェクティブCのAPIの使い方をする場合には、ランタイムのオブジェクティブCのクラスを独自に作る必要が出てきます。この場合には、2つの方法があります:

  •  一般的に使用されているデリゲートパターンを実行する。すなわち、iOS に組み込まれたオブジェクティブCのクラスのコールバックインターフェイスを適用する方法です。
  •  カスタマイズを目的として、オブジェクティブCのクラスのサブクラスに位置付ける。一例として、-drawRect: をオーバーライド(子クラスで親クラスのメソッドを書き換えること)するための UIView のサブクラス化があります。

 これを成し遂げるために、objc_util モジュールには create_objc_class() 関数があります。この関数はオブジェクトCランタイムを新しいクラスに割り当てたり記録したりするほか、上の例の組み込まれたクラスのように使用できるObjCClass オブジェクトをラップします。

 create_objc_class() を使ってオブジェクティブCのクラスを作るには、以下の事柄が必要です:

name – 生成するクラスの名前で文字列型です。文字、数字とアンダースコア(アンダーバー)だけが使用可能で、数字から始めることはできません。実際に生成されるクラスの名前は、これとは異なることがあることに注意して下さい。なぜなら、この名前のクラスは既に存在している場合があるからです。このような場合、新しい名前が自動的に選ばれ、デフォルトで debug パラメーターは True になります。逆に debug が False の場合には、存在しているクラスが返され、他の全てのパラメーターは無視されます。

superclass – 新しいクラスが継承するオブジェクティブCのクラスを決定する ObjCClass オブジェクトです。

methods – 新しいクラスのインスタンスのメソッドを生成するのに使用される関数のリストです。Python の関数からオブジェクティブCのメソッドを生成するためには、オブジェクティブCのランタイムは追加のメタデータを必要とします。セレクターの名前、戻り値の型、引数ごとの型が必要となります。create_objc_class() は、可能な範囲でこのメタデータを引き出そうと努めます。その手順について以下に説明します。

全てのオブジェクティブCのメソッドは、オブジェクティブCから呼び出される際には隠れてしまう、少なくとも2つのパラメーターを必要とします:_self はオブジェクティブCのオブジェクトそのものを示すポインタです。(これはObjCInstance のオブジェクトをラップするものではなく、そのため必要なら別途ラップする必要があることに注意が必要です)そして、_cmdはセレクターを示すポインタです。(通常は必要ありません)これら2つの「隠された」パラメーターの名前は重要ではありません。パラメーターがObjCInstance のオブジェクトではなく、「そのままの」ポインタとしてオブジェクティブCのメソッドに渡されることにご注意ください。但し、オブジェクトのパラメーターはラップするコーディングをすることで簡単に変換することができます。例えば、obj = ObjCInstance(_self)という形で。

classmethods (optional) – クラスのメソッドがなければ、メソッドと同様です。(必要になることは稀です)

protocols (optional) – メソッドの型変換のヒントとして使用する文字列のリストです。デリゲート(またはその他の)プロトコルを実行する場合、全てのメソッドの戻り値と引数の型を確実に正しく推論できるよう、プロトコルの名前(例えば、'UITableViewDataSource')を記述する必要があります。

 以下は、(iOS の標準メールシートを表示するために使用される)MFMailComposeViewController のデリゲートとして動作する、シンプルなクラスを生成する例です。デリゲートはこのクラスの使用に必要不可欠です。なぜなら、他の方法ではメールシートを取り除くことができないためです。(メールシートの使用が終了した際にデリゲートが通知され、それによりシートが開放されます。):

# - (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
def mailComposeController_didFinishWithResult_error_(_self, _cmd, controller, result, error):
    print('Mail composer finished')
    # Wrap the controller parameter in an `ObjCInstance`, so we can send messages:
    mail_vc = ObjCInstance(controller)
    # Set delegate to nil, and release its memory:
    mail_vc.setMailComposeDelegate_(None)
    ObjCInstance(_self).release()
    # Dismiss the sheet:
    mail_vc.dismissViewControllerAnimated_completion_(True, None)

methods = [mailComposeController_didFinishWithResult_error_]
protocols = ['MFMailComposeViewControllerDelegate']
MyMailComposeDelegate = create_objc_class('MyMailComposeDelegate', NSObject, methods=methods, protocols=protocols)

@on_main_thread
def show_mail_sheet():
    MFMailComposeViewController = ObjCClass('MFMailComposeViewController')
    mail_composer = MFMailComposeViewController.alloc().init().autorelease()
    # Use our new delegate class:
    delegate = MyMailComposeDelegate.alloc().init()
    mail_composer.setMailComposeDelegate_(delegate)
    # Present the mail sheet:
    root_vc = UIApplication.sharedApplication().keyWindow().rootViewController()
    root_vc.presentViewController_animated_completion_(mail_composer, True, None)

if __name__ == '__main__':
    show_mail_sheet()

API リファレンス

 クラス

class objc_util.ObjCClass(name)

 引数 name で指定したオブジェクティブCのラッパーです。オブジェクティブCのクラスのメソッドを代理で呼び出します。

 メソッドの呼び出しは、スクリプトの動作の過程でオブジェクティブCのメッセージに変換されます。メソッドの名前の中のアンダースコアがセレクターの名前の中のコロンに置き換えられ、オブジェクティブCのランタイムの中で、セレクターと引数がよりOSに近いレベルの objc_msgSend() 関数を呼び出すことに使われてこの変換が実行されるのです。

 例えば、NSDictionary.dictionaryWithObject_forKey_(obj, key) (Python) の呼び出しは、実際のところ、[NSDictionary dictionaryWithObject:obj forKey:key] (Objective-C)に変換されます。メソッドの呼び出しがオブジェクティブCのオブジェクトを返した場合、それは ObjCInstance をラップしたことになり、呼び出しを結びつけることができます。(ObjCInstance は同様のプロキシの仕組みを使用します)

 いくつかの共通に使用されたクラスはモジュールの要素です。(最後のリストを参照)その他については、クラスの名前を使って単に「インポート」することになります。例:

UIPasteboard = ObjCClass('UIPasteboard')

class objc_util.ObjCInstance(ptr)

 オブジェクティブCのオブジェクトへのポインターのラップです;オブジェクトへメッセージを送る際のプロキシとして動作します。

 メソッドの呼び出しは、スクリプトの動作の過程でオブジェクティブCのメッセージに変換されます。メソッドの名前の中のアンダースコアがセレクターの名前の中のコロンに置き換えられ、オブジェクティブCのランタイムの中で、セレクターと引数が objc_msgSend() 関数を呼び出すことに使われてこの変換が実行されるのです。

例えば、obj.setFoo_withBar_(foo, bar) (Python) の呼び出しは、obj setFoo:foo withBar:bar] (Objective-C)に翻訳されます。メソッドの呼び出しによりオブジェクティブCのオブジェクトが返される場合には、ObjCInstance にもラップされ、言わば結びつけられることになります。

  NSObject メソッドの記述を呼び出すことで ObjCInstance は__str__ and __repr__ を実行します。

 インスタンスが標準的なオブジェクティブCの集合型(NSArray, NSDictionary, NSSet)をラップする場合、標準的なPythonの集合と多くの点で似通った動作をします。イテレート(for..in)できますし、「some_dict['key'], some_array[3]...)」のように、角括弧を使ったキーやインデックスでアイテムにアクセスすることもできます。

class objc_util.ObjCBlock(func, restype=None, argtypes=None)

 ブロックのサポートはまだ実験的なものであることにご注意ください。ブロックを必要としない API を使用する選択肢がある場合には、そちらを強くお勧めします。

 ObjCBlock はオブジェクトCメソッドに対して、blocks (“closures”)を渡して使用することができます。前述の通り、この機能は実験的であり、可能であれば、通常はブロック不要のAPIを使用すべきです。戻り値や引数がないブロックの場合、Python の関数を渡せます。そして、ObjCBlock へ自動的に変換されます。そのほかの場合には、ブロックを作る際、戻り値と引数を明確に設定する必要があります。

 引数のあるブロックの例(NSMutableArrayをカスタマイズした比較関数でソート):

from objc_util import *
cheeses = ns(['Camembert', 'Feta', 'Gorgonzola'])
print(cheeses)

def compare(_cmd, obj1_ptr, obj2_ptr):
    obj1 = ObjCInstance(obj1_ptr)
    obj2 = ObjCInstance(obj2_ptr)
    # Sort the strings by length:
    return cmp(obj1.length(), obj2.length())

# Note: The first (hidden) argument `_cmd` is the block itself, so there are three arguments instead of two.
compare_block = ObjCBlock(compare, restype=NSInteger, argtypes=[c_void_p, c_void_p, c_void_p])

sorted_cheeses = cheeses.sortedArrayUsingComparator_(compare_block)
print(sorted_cheeses)

 関 数

objc_util.autoreleasepool()

 NSAutoreleasePool のラッパーとして動作するコンテキストマネージャーです。 (オブジェクトCの @autoreleasepool {...} に似ています)

 使用例:

  with objc_util.autoreleasepool():

   # do stuff...

objc_util.create_objc_class(name, superclass=NSObject, methods=[], classmethods=[], protocols=[], debug=True)

 引数で与えられたメソッドを実行する新しい ObjCClass を生成して返します。

 セレクターの名前は関数の名前に応じて設定されます。関数の名前には、オプションとして、オブジェクティブCのクラスの名前を前につけることができます。例えば、これら2つの関数は、結果として同じセレクターの名前になります:

def MyClass_doSomething_withObject_(_self, _cmd, foo, bar):
    pass

def doSomething_withObject_(_self, _cmd, foo, bar):
    pass

 # これらの関数は両方とも 'doSomething:withObject:'というセレクターの名前になります。

 戻り値の型と引数の型を決めるため、 create_objc_class() は親クラスが同じセレクターのメソッドを持っているか確認します。同じセレクターのメソッドを持っている場合、親クラスのメソッドから型を継承します。この手法により、子クラスのメソッドにも親クラスの型を継承します。これでうまく行かない場合には、引数 protocols で渡した型が使われます。引数 protocols は文字列のリストです。例えば、 ['UIGestureRecognizerDelegate', 'UITableViewDataSource'] というような。これらの protocols は、同じセレクターのメソッドがあるか確認されます。この手法により、例えば、デリゲートプロトコルが設定されます。それとともに、これらの手法により多くの一般的な場合、型の情報が決められます。これらが上手く動作しない場合には、関数の引数として restype, argtypes, encoding を渡す事もできます。

 注 既に存在しているオブジェクティブCのクラスを使用する場合には、単純にObjCClass(name) を使ってリファレンスを取得して下さい。この関数は、新しいクラス生成します。例えば、オブジェクティブCのクラスの子クラスや、デリゲートプロトコルを設定します。

objc_util.load_framework(name)

 引数 name で指定したシステムフレームワークを読み込みます。(例えば、'SceneKit')

 得られるシステムフレームワークは、オブジェクトCのコードに相当します。[[NSBundle bundleWithPath:@"/System/Frameworks/.framework"] load]

objc_util.ns(obj)

 Python のオブジェクトを ObjC の同等のオブジェクトに変換します。すなわち、str => NSString, int/float => NSNumber, list => NSMutableArray, dict => NSMutableDictionary, bytearray => NSData, set => NSMutableSet という変換をします。リストやディクショナリー、集合型のような入れ子構造にも対応しています。既にObjCInstance のインスタンスになっているオブジェクトについては、変換せずそのまま返します。

 オブジェクティブCのメソッドがパラメーターとしてオブジェクトと推定される場合、Python オブジェクトのパラメーターは自動的にこの関数を使って変換され、例えば、Python の文字列は NSString としてオブジェクティブCのメソッドに渡すことができるようになります。

objc_util.nsurl(url_or_path)

 Python の文字列をNSURLのオブジェクトに変換します。(ObjCInstance でラップします)

 引数 url_or_path の文字列にコロン ‘:’ が含まれている場合、文字列はフルURLとして扱われ、+URLWithString: を使って NSURL に変換されます。それ以外の場合、+fileURLWithPath: を使ってファイルのURLが生成されます。

objc_util.nsdata_to_bytes(data)

 ObjCInstance でラップされた NSData オブジェクトを Python のバイト文字列に変換します。

objc_util.uiimage_to_png(img)

 ObjCInstance でラップされた UIImage オブジェクトを Python の PNG データで構成されたバイト文字列に変換します。

objc_util.on_main_thread(func)

 UIKit のメインスレッド上の関数(引数 func で指定)をデコレートする関数です。多くのオブジェクティブCの API、特に UIKit は、メインスレッドから呼び出す必要があります。一般的に、その他の関数をデコレートするために使われますが、例えば on_main_thread(my_function)(param1, param2) のように、特別にメインスレッドへの関数呼び出しを割り当てるために使用することもできます。

 以下はデコレーターの例です:

from objc_util import *

@on_main_thread
def post_notification(name):
    NSNotificationCenter = ObjCClass('NSNotificationCenter')
    center = NSNotificationCenter.defaultCenter()
    center.postNotificationName_object_(name, None)

# 全ての post_notification(...) の呼び出しは、on_the_thread で発生します。 

objc_util.sel(name)

 sel_registerName の便利なラッパーです。(Python の文字列をオブジェクティブCのセレクターに変換します)

 オブジェクティブCのクラスと構造体

 利便性を考えて、いくつかの共通して使われるオブジェクティブCのクラスや構造体は、モジュールレベルのオブジェクトとして使用可能になっています。そのため、以下のクラスと構造体については、明確にラップする必要はありません:

class objc_util.CGPoint

class objc_util.CGSize

class objc_util.CGVector

class objc_util.CGRect

class objc_util.CGAffineTransform

class objc_util.UIEdgeInsets

class objc_util.NSRange

class objc_util.NSDictionary

class objc_util.NSMutableDictionary

class objc_util.NSArray

class objc_util.NSMutableArray

class objc_util.NSSet

class objc_util.NSMutableSet

class objc_util.NSString

class objc_util.NSMutableString

class objc_util.NSData

class objc_util.NSMutableData

class objc_util.NSNumber

class objc_util.NSURL

class objc_util.NSEnumerator

notification — iOSの通知機能

 notification モジュールを使うことにより、iOS の通知センター画面に、予約した通知メッセージを表示することができるようになります。予約通知メッセージは、pythonista 上のスクリプトを実行していなくても、pythonista そのものが起動されていなくても表示されます。

 通知に URL アドレスを添付することも可能です。通知センター画面やロック画面で通知をタップし、通知をアクティベートすれば、この URL で指定した HP を表示できます。通知に複数のボタンを配置し、それぞれに個別の URL を立ち上げるよう設定することもできます。

 一般的には、予約通知は未来の特定の日時に表示されるよう設定しますが、家とか仕事先のような特定の場所に到着したり離れたりしたことをトリガーとする、場所に基づいた予約もできます。

 このモジュールの通知機能は、「ローカルな」通知専用です。不特定多数の人に通知する、いわゆるプッシュ通知はサポートされていません。

関 数

notification.schedule(message=None, delay=0, sound_name=None, action_url=None, title=None, subtitle=None, attachments=None, trigger=None, actions=None, identifier=None)

 後述するパラメーターで指定した通知機能の実行を予約します。

 戻り値は、後で通知をキャンセルする際などに使用できる通知のIDとなる文字列です。

パラメーター:

  • message: 通知で表示するテキスト本文です。
  • delay: 通知を届ける時刻を現在からの秒単位で設定します。
  • sound_name: 通知が届いた際に鳴らしたい、システムに組み込まれている効果音や音楽ファイルの名前を指定します。通知時に無音またはデフォルトの通知オン設定をしている場合には、None にしておくことができます。
  • action_url: 通知をタップした際に立ち上げるURLを指定します。
  • title: 通知を画面表示した時にメッセージの上に表示するタイトルを設定します。
  • subtitle: 通知のサブタイトルを設定します。
  • attachments: 通知に添付する画像などファイルのリストです。これらのファイルは即座にコピーされ、後からの変更は効かないことにご注意下さい。
  • trigger: 単純な経過秒数ではなく、後述する複雑なトリガーを記述したディクショナリーです。
  • actions: 通知に埋め込んだボタンがタップされた時の挙動を記述します。ボタンが複数ある場合には、それぞれのボタンは別々の URL を開いたり、スクリプトを実行したりするよう設定可能です。通知に付随したアクションは、スクリーン上端の通知バナーをドラッグして下にスライドするか、3Dタッチ(サポートしている機種のみ)か、通知をタップしホールドし続ける(3Dタッチ未対応の機種の場合)のいずれかで実行できます。個々のアクションの定義の仕方の詳細については、後述します。
  • identifier: 通知のIDとして使用するための付加的な文字列です。既に予約された通知と同じIDの通知を予約した場合には、古い通知は新しい通知に置換えられます。

日時や場所によるトリガー:

 単純な残り時間設定ではなく、より複雑な通知のトリガーが必要な場合、トリガーのパラメーターをディクショナリー型で関数に渡すことができます。このトリガーには、日付に基づくものと場所に基づくものの多くの選択肢があります。日付に基づく通知のキーとしては、'repeats', 'year', 'quarter', 'month', 'day', 'weekday', 'weekday_ordinal', 'week_of_month', 'week_of_year', 'hour', 'minute', 'second'がサポートされています。これらの全てのキーを指定する必要はなく、必要に応じてdate/time コンポーネントを使用すれば十分です。繰り返し通知は1分間に1回以上の短い周期での繰り返しはできません。

 場所に基づく通知のキーとしては、 'latitude', 'longitude', 'radius' (単位メートル、デフォルト値は100), 'entry', 'exit', 'repeats'がサポートされています。'entry'(指定地点への到着を知らせる)と'exit'(指定地点からの退出を知らせる)オプションは、True または False に設定します。デフォルトでは、両方とも True になっています。場所に基づく通知には、アプリに対して位置情報のアクセスの許可が必要です。(自動的に許可を求める表示がなされ、設定>プライバシーで変更をすることができます)

通知に付随したアクションのカスタマイズ:

 アクションに関するパラメーターは、(例えば、ロック画面での3Dタッチにより)通知がアクティベイトされた際にボタンの形で表示される、アクションのリストとして設定することができます。アクションは以下のキーからなるディクショナリー型のリストで定義します:

  • 'title' – ボタンのタイトル
  • 'url' または 'action_url' – ボタンがタップされた際に表示される URL です。この URL が pythonista:// から始まる URL の場合には、スクリプトを実行します。次項目の 'foreground' が True に設定されていない場合は、スクリプトはバックグラウンドで実行されます。
  • 'foreground' – 'action_url' を参照。
  • 'destructive' – 誤って操作した場合に致命的な結果をもたらすボタンの見た目を変えます。(文字色を赤にします)
  • 'text_input' – True に設定すると、通知画面の中にテキスト入力画面を表示させることができるようになります。入力したテキストデータを使用するには、'url' キーで指定するアクションの URL に {text_input} というプレースホルダー(テキスト入力値の挿入位置指定の記号)を配置して下さい。このアクションでスクリプトを実行するために pythonista:// から始まる URL を使用した場合には、入力したテキストデータを URL の引数パラメーターとして使用し、スクリプト中で sys.argv によりアクセスすることができます。(例)pythonista3://MyScript.py?action=run&args={text_input}
  • 'text_input_button_title' – 'text_input' が True の時、ボタンのタイトルを「OK」に指定します。
  • 'text_input_placeholder' – 'text_input' が True の時、プレースホルダーのテキストを指定します。

notification.cancel(identifier)

 以前に予約されていた通知をキャンセルします。

 キャンセルする通知を指定する引数 identifier には、get_scheduled() で呼び出した文字列か、 schedule() 関数の戻り値の文字列を使用します。

notification.cancel_all()

 以前に予約していた通知を全てキャンセルします。

notification.get_scheduled()

 予約した通知のIDのリストを返します。

 リストの各項目は、cancel() 関数に使用できる UUID 文字列です。

notification.remove_delivered(identifier)

 通知センターに表示され終わった、引数 identifier で指定した通知を削除します。注:ユーザーが通知をアクティベイトすると、この処理は自動的に行われます。

notification.remove_all_delivered()

 通知センターに表示され終わった、全ての通知を削除します。注:このアプリの通知のみに適用されます。

motion — iOS 上のモーションセンサーデータ

  motion モジュールは iOS デバイスのモーションセンサーのデータ(加速度センサー、ジャイロセンサー、磁気センサー)へのアクセスを可能にします。

motion モジュールの関数

motion.start_updates()

 iOS デバイスのモーションセンサーのモニタリングを開始します。電池の消耗を考慮するなら、適度なタイミングで stop_updates() を呼び出してモニタリングを終了させる必要があります。全ての get…から始まる関数は、予めこの start_updates() を呼び出しておく必要があります。呼び出すのを忘れた場合には、意味のあるデータは返されません。

motion.stop_updates()

 iSO デバイスのモーションセンサーのモニタリングを終了します。

motion.get_gravity()

 重力のベクトル(x, y, z)を返します。

motion.get_user_acceleration()

 ユーザーがデバイスに与えた加速度を返します。加速度の総和は、get_gravity() か返す重力ベクターとユーザーの加速度を足したものになります。

motion.get_attitude()

 デバイスの向いている方向(ピッチング、ローリング、ヨーイング)を返します。

motion.get_magnetic_field()

 デバイスに対する磁界のベクトル(x, y, z, accuracy)を返します。(注 accuracy:正確さ)

location — iOS 上の位置情報サービス

 location モジュールは、iOS 上のGPSなどの位置情報データへのアクセスを可能にします。加えて、住所を緯度軽度に変換したり、その逆に変換するのにも使えます。

 (注 最初にこのモジュールを使用する際に、iOS からの位置情報サービスを使用する許可を求めるダイアログが表示されます。Pythonista アプリに位置情報へのアクセスを許可しないと、以下の関数の多くは正しい値を返しません。)

location モジュールの関数:

location.get_location()

 入手した中で、最新の位置情報データを返します。戻り値は現在の位置を示す多くの値のディクショナリー型になっています。(最も大事なのは「緯度」「経度」「タイムスタンプ」です。)このディクショナリーは reverse_geocode() 関数の引数としても使えます。位置情報データが得られていない場合(あるいは Pythonista に位置情報へのアクセスを許可していない場合)には、None を返します。

location.start_updates()

 位置情報データの更新を開始します。get_location() を使用する前に必ず呼び出す必要があります。省エネのためには、位置情報が不要になったら stop_updates() を呼び出すことをお勧めします。

location.stop_updates()

 位置情報の更新を停止します。

location.geocode(address)

 引数 address の住所のディクショナリーから緯度経度への変換を行います。戻り値は該当する緯度経度のリストです。見つからなかった場合には空のリストを返します。リストの形式は、「緯度」(latitude)と「経度」(longitude)をキーとするディクショナリー型です。

 例)

import location
address_dict = {'Street': 'Infinite Loop', 'City': 'Cupertino', 'Country': 'USA'}
results = location.geocode(address_dict)
print(results)

location.render_map_snapshot(lat, lng, width=1000, height=1000, map_type='standard', show_poi=True, img_width=240, img_height=240, img_scale=0)

 引数で指定した範囲の地図画像をアップルの地図システムを使用して表示します。

 引数の lat(緯度)と lng(経度)で地図の中心を指定します。引数 width と height (単位はメートル)は地図の縮尺の設定の際に考慮されます。引数 map_type は「stndard」、「satellite」、「hybrid」のいずれかに設定します。

 戻り値は引数 img_width と img_height で指定したサイズと引数 img_scale(デフォルトではゼロ、すなわち使用しているデバイスの画面のスケール)で指定した縮尺の ui.image です。

 例)

import location
img = location.render_map_snapshot(48.8582, 2.2945, map_type='satellite', img_width=512, img_height=512)
img.show()
location.reverse_geocode(location)

 次に、緯度経度で表された場所を人が読んで分かる住所に変換してみましょう。場所を示す引数は、latitude(緯度) と longitude(経度) の値からなるディクショナリー型です。戻り値は(通常は単一の)住所のディクショナリー型のリストになります。

 例)

import location
coordinates = {'latitude': 37.331684, 'longitude': -122.030758}
results = location.reverse_geocode(coordinates)
print(results)

location.is_authorized()

 位置情報のアクセスが許可されている場合には True を、許可されていない場合には False を返します。(例えば、許可ダイアログがまだ表示されていない時や、ペアレンタルコントロールでアクセスが禁止されている場合など)

linguistictagger — 言語解析

 linguistictagger モジュールは自然言語のテキストを分解し、品詞のような情報のタグ付けをするのに使用します。

 このモジュールが提供するのは単一の機能です:

linguistictagger.tag_string(string, scheme)

 引数 string で与えられた文に、引数 scheme に応じたタグ付けをします。scheme に使用できる定数については、後述します。

 戻り値は要素数が3つのタプルのリストです。それぞれのタプルは、タグ、タグ付けされた部分文字列、元の文字列の中の部分文字列の位置、の3要素で構成されています。

 例:

import linguistictagger as lt
text = 'Python is pretty awesome.'
results = lt.tag_string(text, lt.SCHEME_LEXICAL_CLASS)
for tag, substring, range in results:
    if tag != 'Whitespace':
        print (substring,  ": ", tag)

定 数

linguistictagger.SCHEME_TOKEN_TYPE

 文字列中のトークンを大雑把なタイプ(単語、句読点、スペースなど)に分類します。

linguistictagger.SCHEME_LEXICAL_CLASS

 文字列中のトークンをクラス(単語の品詞、句読点、スペースなど)に分類します。

linguistictagger.SCHEME_NAME_TYPE

 文字列中のトークンを、名付けられた具体的な物(人名、地名など)か、そうでないかを分類します。

linguistictagger.SCHEME_NAME_TYPE_OR_LEXICAL_CLASS

 文字列中のトークンに対して、名付けられた具体的な物か、品詞、句読点、スペースなどのタグ付けをします。

linguistictagger.SCHEME_LEMMA

 辞書に該当する項目がある場合、単語の原形(語幹)を返します。

linguistictagger.SCHEME_LANGUAGE

 トークンごとに言語の種類を示すタグを付けます。タグの値は、標準的な言語の「en」(英語)、「fr」(フランス語)、「de」(ドイツ語)、「ja」(日本語)などの省略形です。なお、言語分類の判定は通常、単語ごとではなく、文や段落全体のレベルで行われることにご注意下さい。

linguistictagger.SCHEME_SCRIPT

 トークンの文字種類に応じて分類してタグ付けします。タグの値は「Latn」(ラテン文字)、「Cyrl」(キリル文字)、「Jpan」(漢字)、「Hans」(簡体字)、「Hant」(繁体字)などのように標準的な文字種類の省略形です。

keychain — 安全なパスワード保管庫

 keychain モジュールは、安全なパスワード保管庫への簡易なアクセスを提供します。

 keychain はアプリ間では共有されないことにご注意下さい。例えば、 Safari の keychain に保管されているパスワードにはアクセスできません。

keychain.get_password(service, account)

 引数 service や account で指定したサービスやアカウントについて、予め keychain に保管しておいたパスワードを取り出します。

keychain.set_password(service, account, password)

 引数 service や account で指定したサービスやアカウントに関するパスワードを keychain に保管します。

keychain.delete_password(service, account)

 引数 service や account で指定したサービスやアカウントに関するパスワードを keychain から削除します。

keychain.reset_keychain()

 keychain からすべてのデータを削除します。

keyboard — Pythonista キーボードのためのユーティリティー

はじめに

 keyboard モジュールには Pythonista に付属のキーボード(PyKeys)を拡張するための様々な関数が用意されています。

 Pythonista 付属のキーボードは、 iOS 上のテキストの編集機能をもった非常に多くのアプリで使用されている画面上のキーボードです。スクリプトを書いてこのキーボードを拡張し、例えば、短いテキストを挿入したり、QWERTYキーボード上に全く独自のUI(ui.View)を使えるようにすることができるようになります。この独自の UI については、追加ボタンの表示をさせたり、ドキュメントや選択に応じて反応を変えたりすることもできます。

 もし、キーボード用のスクリプトにカスタマイズした view や UI を用意する場合には、カーソルを動かすとか付属のQWERTYレイアウトのキーを使うなどの、何らかのテキスト入力に関連したイベントが発生した際に通知を受けることできます。この目的のために、独自の ui.View サブクラスに以下のコールバックメソッドを設けることができます:

import keyboard
import ui
from datetime import datetime
from random import uniform

class MyView (ui.View):
        def __init__(self, *args, **kwargs):
                self.label = ui.Label(frame=self.bounds, flex='wh')
                self.add_subview(self.label)
                super().__init__(*args, **kwargs)

        def kb_should_insert(self, text):
                self.label.text = f'Insert: {text}'
                # You can modify the inserted text here:
                return text

        def kb_text_changed(self):
                self.background_color = (uniform(0.5, 1.0), uniform(0.5, 1.0), uniform(0.5, 1.0))

        def kb_should_delete(self):
                return True


v = MyView()
keyboard.set_view(v)

 独自のキーボードのユーザーインターフェイスについて、Pythonista の「keyboard examples」フォルダに多くの例が用意されています。

 Pythonista のショートカットのページに、キーボードを表示させたり使用したりする方法についてより詳細な情報があるので参照ください。

Functions

keyboard.backspace(times=1)

 現在のドキュメントを後退しながら削除します。(バックスペースキーと同様に動作します)引数の times で一度にどれだけの文字を削除するかを設定します。

keyboard.get_appearance()

 キーボードの現在の見た目(ダークモードかライトモード)を返します。

keyboard.get_document_id()

 キーボードでタイピングしている、現在のドキュメントのUUID(Universally Unique IDentifier)を返します。このIDは任意かつランダムであり、ドキュメントに関する情報を含んでいませんが、ユーザーが別のドキュメントのタイピングをしていることを判定するのに使用できます。

keyboard.get_input_context()

 カーソルのすぐ前と後のテキストの文字列の2つのタプルを返します。

keyboard.get_selected_text()

 現在選択しているテキスト、または選択していない場合には空の文字列を返します。

 (警告 2行以上、または1,000文字以上を選択した場合、この関数の戻り値は途中で途切れてしまいます。この現象は残念なことに、システム上の制約であり、技術的に解決することができません。さらには、途中で途切れたことを検知する方法もありません。

 一般的には、この関数の戻り値が複数行ある場合には、選択したテキストの置き換えに使うべきではありません。

keyboard.get_text_replacements()

 キーボードのグローバル設定(「設定>一般>キーボード>ユーザー辞書」で設定した内容)のユーザー辞書のリストを返します。ユーザー辞書は「文字列」と「読み仮名」の2要素のタプルになっています。

 この関数は Pythonista キーボードが表示されている時のみ実行可能です。その他の状況では、None を返します。

keyboard.has_full_access()

 キーボードへの「フルアクセス」が許されている時には True を返します。その他の場合には False を返します。

 「フルアクセス」は、例えばネットワークへのアクセス、クリップボード、メインアプリにファイルを書き込む時などに必要になります。

keyboard.has_text()

 キーボードで編集しているドキュメント(テキストフィールド)に何らかの文字がある場合には True を返します。空の場合には False を返します。

keyboard.insert_text(text)

 キーボードで編集している現在のドキュメント(またはテキストフィールド)にテキストを挿入します。

keyboard.is_keyboard()

 pythonista キーボードでスクリプトが実行されている場合には True を返します。その他の場合には False を返します。

 この関数は、キーボードで実行した場合とメインアプリで実行した場合とで異なる挙動をする必要があるスクリプトに使用できます。

keyboard.move_cursor(offset)

 引数 offset で(正または負の整数で)指定した位置にカーソルを移動させます。

keyboard.play_input_click()

 入力の際のクリック音を出します。この機能はユーザーが「設定>サウンド>キーボードのクリック」でクリック音が許可されていて、デバイスが消音になっていない場合に実行されます。

keyboard.set_view(view=None, mode='current')

 キーボードのユーザーインターフェイスとして ui.View を設定します。modeが「minimized」の場合にはQWERTYレイアウトの上方、「expanded」の場合にはキーボードエリアの大部分を埋めるような形で機能します。「current」の場合にはアクティブモードが継続します。(緑の「ショートカット」キーをタップすれば手動で切り替えられます)

 view に None を設定して呼び出すことで、現在のビューを閉じることができます。

 テキスト入力イベントの発生を把握するための、独自のUIを設定できるコールバックの情報については「はじめに」をご覧ください。

editor — Pythonista のテキストエディターのスクリプトへのアクセスのための関数

 editor モジュールは現在編集中のスクリプトへのアクセスを提供します。指定した範囲のテキストを取得したり設定したり、置き換えをすることができます。

 (注 選択可能な範囲を越えるなどの選択に関する誤った入力値や、テキスト操作関数に関する誤入力については、警告を出さず静かに無視するだけにしています。この部分は今後のアップデートの際に変更するかも知れません。)

 このモジュールは、バージョン1.1で新規に導入したカスタマイズ可能なアクションメニューと組み合わせると非常に便利です。現在編集中のスクリプトとは関係なく、あなたのライブラリーのどんなスクリプトでもエディターから素早く実行できるようメニューに追加することができます。このメニューは設定で変更することができます。(Editor > Actions Menu)

 (注 翻訳者の使用しているver3.3の環境では、この部分は変更になっているようです。)

 以下のスクリプトは、Pythonista アプリそのものの能力を拡張できる可能性があります。アクションとして情報の断片にアクセスすることで、着想を得ることができます:

# 選択したテキストを開発者用ウェブサイト「StackOverflow」内で探す

import editor
import webbrowser

text = editor.get_text()
s = editor.get_selection()
selection = text[s[0]:s[1]]
if len(selection) > 0:
    from urllib.parse import quote
    q = quote(selection)
    search_url = 'http://stackoverflow.com/search?q=' + q
    webbrowser.open(search_url)
else:
    from console import alert
    i = alert('No Selection', 'Do you want to open the StackOverflow homepage?', 'StackOverflow')
    if i == 1:
        webbrowser.open('http://stackoverflow.com')

 このサンプルでは、選択したテキストを人気Q&Aサイトである「StackOverflow」で検索します。テキストが選択されていない場合には、代わりにこのウェブサイトを開くかどうかを確認するダイアログをポップアップ表示します。

 余談ですが、webbrowser モジュールはアプリ独自のURLルールを実行できます。例えば、ツイートbotをwebbrowser.open('tweetbot:///post?text=Hello)の形で立ち上げることもできます。

 以下の例は、get_line_selection() の便利な機能を用いて、どのようにしたら選択した行の先頭にコメントを示す「#」を付けたり外したりできるかを示したものです。コメントにしたい行の全てを選択しなくても、タッチした全ての行に対して実行します:

#Comment/Uncomment selected lines

import editor

text = editor.get_text()
selection = editor.get_line_selection()
selected_text = text[selection[0]:selection[1]]
is_comment = selected_text.strip().startswith('#')
replacement = ''
for line in selected_text.splitlines():
    if is_comment:
        if line.strip().startswith('#'):
            replacement += line[line.find('#') + 1:] + '\n'
        else:
            replacement += line + '\n'
    else:
        replacement += '#' + line + '\n'

editor.replace_text(selection[0], selection[1], replacement)
editor.set_selection(selection[0], selection[0] + len(replacement) - 1)

 以下の関数は editor モジュールに含まれています。

editor.get_path()

 現在エディター上に開いているスクリプトの絶対パスを返します。

 スクリプトを開いていない場合、None を返します。

editor.get_text()

 編集中のスクリプトの全てのテキストを返します。

 編集内容を全て保存していない場合には、get_path() で返されるファイルを読み込むのとは異なることに注意してください。

editor.get_selection()

 選択した範囲の始点と終点の形式のタプルとして返します。

 エディターでファイルを開いていない場合には、None を返します。

editor.get_line_selection()

 選択した全ての行の範囲を開始行と終了行の形式のタプルとして返します。

 エディターでファイルを開いていない場合には、None を返します。

editor.set_selection(start, end=None, scroll=False)

 エディターで開いているテキストの中で、引数 start と end で指定した範囲を指定します。

 start と end は整数値で指定して下さい。end が None の場合には、テキストは選択せず挿入記号(プロンプト)を start で指定した場所に表示します。

editor.replace_text(start, end, replacement)

 引数 start と end で指定した範囲のテキストを引数 replacement で置換します。

 テキストを挿入(又は追加)したい場合には、start と end を同じ場所(範囲の長さをゼロ)にして下さい。

 全ての変更については、通常のアンドゥキーを使って元に戻すことができます。何回かに分けて呼出した場合には、影響した文字数に関わらず、それぞれの段階まで元のスクリプトに回復できます。

editor.make_new_file([name, content])

 エディターで新しいファイルを新規作成し、開きます。

 引数 name で与えたファイル名のファイルが既に存在している場合には、ファイル名の後に番号を自動的に付加します。引数 content の内容は、新しいファイルの中にテキストとして配置されます。省略した場合には、中身が空のファイルを生成します。

 現在開いているファイルは、新しいファイルを開く前に、自動的に保存されます。

editor.open_file(name, new_tab=False)

 引数 name で指定したファイルをエディターで開きます。

 名前はスクリプトライブラリーの保管場所からの相対パスのほか、絶対パスでも付けられます。

 拡張子「 .py」は省略することもできます。エディターで開いていたファイルは自動的に保存されます。

editor.apply_ui_theme(ui_view, theme_name=None)

 ui.View とそこから派生した View を、引数 ui_view と theme_name で指定した UI テーマに設定します。

 theme_name が None(デフォルトです)がない場合、現在選択されているテーマが使用されます。その他の場合、設定にある通りのテーマ名でなければなりません。

editor.present_themed(ui_view, theme_name=None, **kwargs)

 ui.View とそこから派生した VIew を apply_ui_theme() を使って引数で指定した UI テーマに設定して表示します。

 引数の **kwargs(Keyword arguments) は、title_bar_color と title_color を除き ui.View.present() に渡されて、UI テーマに自動的に設定されます。

editor.annotate_line(lineno, text='', style='warning', expanded=True, filename=None, scroll=False)

 エディターで開いているコード行にラベルをつけます。

 引数 lineno は、ファイルの1から始まる行番号でなければなりません。

 引数 style には、‘success’, ‘warning’ または ‘error’ を設定します。

 引数 expanded が False の場合、アイコンのみ表示します。アイコンをタップすると、注釈の文字を表示されます。その他の場合、文字は即座に表示されます。

 引数 filename が None の場合、エディターに現在開かれているファイルの行に注釈を付けます。

 引数 filename や 引数 lineno が不適切な場合には、エラー表示などをすることなく無視します。

editor.clear_annotations(filename=None)

 annotate_line() で付けられた注釈を削除します。

contacts — iOSの住所録データベースへのアクセス

 contacts モジュールは iOS の contacts(住所録)データベースを読み込んだり、修正したりするために使用します。

(注 最初にcontacts モジュールをインポートした際に、iOS の許可ダイアログが表示されます。住所録へのアクセスを許可しなかった場合、get_all_people() の戻り値は常に空のリストになります。このモジュールを使用する場合には、「設定」>「プライバシー」で住所録へのアクセスを許可して下さい。)

クイックスタート

住所録の情報を読み込む簡単な例として、「電話番号」フィールドにデータがある全ての人の名前と電話番号を画面表示するスクリプトを以下に示します。

(注 本来のマニュアルでは、住所録の「メモ」欄にデータがある全ての人について表示するスクリプトとなっていましたが、iOS13から住所録のメモ欄へのアクセスが禁止されましたので、「電話番号」欄にデータがある全ての人を対象にするようスクリプトを修正しました。)

import contacts
print('Address Book Notes')
print('=' * 40)
people = contacts.get_all_people()
for p in people:
  phone = p.phone
  if phone:
    print(p.full_name)
    print('-' * 40)
    print(phone)
    print('=' * 40)
 

このスクリプトでは get_all_people() 関数を、住所録の全ての人のオブジェクトのリストを呼び出すために使用しています。このリストをイタレートして、 Person.phone フィールドにデータの入っている人全員の名前と電話番号を表示します。

 もう少し複雑な例として、こちらは「もうすぐ誕生日」(誕生日までの残り日数)のリストを表示するスクリプトです。

CopyOpen in Editor
import contacts
from datetime import datetime
import operator

days_list = []
people = contacts.get_all_people()
now = datetime.now()
for p in people:
  b = p.birthday
  if b:
    next_birthday = datetime(now.year, b.month, b.day)
    if next_birthday < now:
      next_birthday = datetime(now.year + 1, b.month, b.day)
    days = (next_birthday - now).days
    days_list.append({'name': p.full_name, 'days': days})

if not days_list:
  print("You don\'t have any birthdays in your address book.")
else:
  days_list.sort(key=operator.itemgetter('days'))
  print('Upcoming Birthdays')
  print('=' * 40)
  for item in days_list:
    print('* %s in %i days' % (item['name'], item['days']))

 「メモ」欄と「誕生日」欄は1人の人に1つしかないので扱いが非常に簡単です。他の多くの欄(フィールド)は、例えば e-mail アドレスを複数持つ人もいるなど、複数の値があり得ます。これらの欄は複数のタプルのリストから成り立っています。これらのタプルは「home」や「work」などのラベルと実際の値から構成されています。一例として、Person.email は [('home', 'me@example.com'), ('work', 'work@example.com')]というような形になっています。

 ここまでは住所録データベースから情報を読み込むだけでしたが、contacts モジュールを使って編集することもできます。先ほどまでの例では単純な一つの値だけの属性を使っていましたが、次の例ではもう少し複雑な Person.address 属性を扱ってみましょう。この属性には複数のディクショナリー型のリストがあり、このリストは「home」とか「work」のようなラベルを含むタプルの要素として構成されています。

 次の例では、ベルリンに住んでいる人々の国名をドイツに修正してみます:

import contacts
people = contacts.get_all_people()
for p in people:
  changed = False
  addresses = p.address
  for address_tuple in addresses:
    address = address_tuple[1]
    city = address.get(contacts.CITY, None)
    country = address.get(contacts.COUNTRY, None)
    if city == 'Berlin' and country != 'Germany':
      address[contacts.COUNTRY] = 'Germany'
      address[contacts.COUNTRY_CODE] = 'de'
      changed = True
  if changed:
    p.address = addresses
    print('Updated country of', p.full_name)
contacts.save()
print('Done')

 住所のディクショナリー型のキー値として定数を使用していることにお気づきでしょうか。これらのキー値のリストについては、このドキュメントの末尾に記載しています。住所録に修正を加えたら、修正内容の保存のため save() 関数を呼び出す必要があります。

 複数の値を持つ属性については「スナップショット」として値を返します。これらのリストを直接操作しても、属性を再びアサインしないと操作内容は保存されません。

Functions

contacts.get_group(group_id)

 引数 group_id(整数、Group.id を参照)に該当する Group を返します。

contacts.get_all_groups()

 住所録の中の全ての Group オブジェクトのリストを返します。

contacts.add_group()

 住所録に Group を追加します。

contacts.remove_group(group)

 住所録から Group を一つ削除します。

contacts.add_person(person)

 住所録に1人の Person を追加します。

contacts.remove_person(person)

 住所録から一人の Person を削除します。

contacts.find(name)

 引数 name で前方一致検索し、合致した Person レコードのリストを返します。

contacts.get_all_people()

 住所録中の全員のリストを返します。それぞれのリストの項目は Person オブジェクトになっています。

contacts.get_person(person_id)

 引数 person_id(整数値、Person.id を参照) に該当するPerson を返します。

contacts.save()

 編集中の変更内容全てを contacts データベースに保存します。Group や Person オブジェクトに変更を加えたら、変更を保存するため、この関数を呼び出さなければなりません。

contacts.revert()

 全ての変更を contacts データベースの内容に戻します。

contacts.localized_label(label)

 複数の値を持つ項目の中で使用されるラベルのローカライズ版を返します。 Return a localized version of a label that is used in a multi-value property.

contacts.is_authorized()

 住所録へのアクセスが許可されている場合には True を、許可されていない場合には False を返します。(例えば、許可ダイアログがまだ表示されていない場合や、ペアレンタルコントロールでアクセスが禁止されている場合などは False となります)

Group オブジェクト

class contacts.Group

 Group オブジェクトは、「友人」、「家族」、「同僚」などを要素として、住所録の中で一つだけ設定されます。Group オブジェクトを初期化し、その名称の属性を設定すると、add_group() を呼ぶことで、住所録データベースに追加することできます。要素の名前を修正したい時には、save() 関数を呼び出して、修正内容を保存する必要があります。

Group.name

 「友達」とか「家族」のようなグループの名称です。

Group.id

 住所録の group レコードの固定ID(整数型、読込のみ)です。group が保存される前の場合は−1を返します。IDは get_group() 関数で使用可能です。

Person オブジェクト

class contacts.Person

Person オブジェクトは住所録に保存された人々を示します。Person オブジェクトを初期化し、属性を設定したら、add_person() 関数を呼び出すことで住所録データベースに追加することができます。属性を修正した場合は save() 関数を呼ぶことで修正内容を保管できます。

 多くの属性について、複数の値を持つことができます。例えば、1人の人が「仕事用」「プライベート用」など複数のe-mailアドレスを持ったり、「家電」「携帯」など複数の電話番号を持つ、などです。これらの属性は、ラベルと実際の値のタプルからなるタプルを要素としたタプルのリストという構成になっています。例えば、1人の人の e-mail については、以下のような構成になっています:

[('home', 'foo@work.com'), ('work', 'foo@work.com')]

 ラベルとしてどんな文字列でも使うことができますが、この説明書の最後に記した定数を使うことをお勧めします。これらのラベルは '_$!!$'のような形式ですが、iOS のユーザーインターフェイス特有のものです。また、localized_label() 関数を使えば地域固有のラベル用定数を調べることができます。

Person.address

 一つあるいは複数の住所(複数のディクショナリー型)です。キー値として contacts.STREET, contacts.CITY, contacts.STAT などの定数を使用することができます。

Person.birthday

 誕生日(daytime.daytime型)です。

Person.creation_date

 人の情報を住所録に追加した時期(読込み限定、datetime.datetime型)です。

Person.department

 所属(文字列型)です。

Person.email

 E-mail アドレス(複数の文字列型)です。

Person.first_name

 ファーストネーム(文字列型)です。

Person.first_name_phonetic

 ファーストネームの読み仮名(文字列型)です。

Person.full_name

 人のフルネーム(読込み限定、文字列型)です。名前を修正するには、Person.first_name, Person.last_name and Person.middle_nameの各属性を使用します。

Person.id

 住所録の個人データのレコードの固定ID(整数型、読込み限定)です。個人データを保存する前には−1を返します。IDは get_person()関数で使用することができます。

Person.image_data

 個人の画像イメージです。例えば、写真の場合、PNGやJPEGのような一般的な画像ファイル形式を示すバイト文字列型を返します。なお、画像が設定されていない場合にはNoneを返します。

Person.instant_message

 インスタントメッセージのアカウント(複数のディクショナリー型)です。

Person.job_title

 職業(文字列型)です。

Person.kind

 住所録のレコードの種類(整数型、0なら「個人」、1の場合「組織」を意味します)

Person.last_name

 ラストネーム(文字列型)です。

Person.last_name_phonetic

 ラストネームの読み仮名(文字列型)です。

Person.middle_name

 ミドルネーム(文字列型)です。

Person.middle_name_phonetic

 ミドルネームの読み仮名(文字列型)です。

Person.modification_date

 個人の情報を最後に修正した時期(読込み限定、datetime.datetime型)です。

Person.nickname

 ニックネーム(文字列型)です。

Person.note

 メモ(文字列型)です。

(注 iOS13以降ではアップル社の方針によりメモへのアクセスは許可されなくなっています。)

Person.organization

 所属組織(文字列型)

Person.phone

 電話番号(複数の文字列型)

Person.prefix

 「サー」「公爵閣下」「大佐」などのような名前の前につける尊称(文字列型)です。

Person.related_names

 関係性(複数の文字列型)です。

Person.social_profile

 SNSでのプロファイル(例えば Twitter のアカウントなど。複数のディクショナリー型)です。

Person.suffix

 「Jr.」「Sr.」「3世」など、名前の後につける接尾語(文字列型)です。

Person.url

 例えばホームページなどのURL(複数の文字列型)です。

Person.vcard

 個人データの VCard (読込み限定、文字列型)です。

定数

複数の値を持つ属性の一般的なラベル:

contacts.HOME

contacts.WORK

contacts.OTHER

 Person.phone の複数の文字列を持つ属性のラベル:

contacts.IPHONE

contacts.MAIN_PHONE

contacts.HOME_FAX

contacts.WORK_FAX

contacts.OTHER_FAX

contacts.PAGER

 Person.related_names の複数の文字列を持つ属性のラベル:

contacts.FATHER

contacts.MOTHER

contacts.PARENT

contacts.BROTHER

contacts.SISTER

contacts.CHILD

contacts.FRIEND

contacts.SPOUSE

contacts.PARTNER

contacts.ASSISTANT

contacts.MANAGER

 Person.url の複数の文字列を持つ属性のラベル:

contacts.HOMEPAGE

 Person.address のディクショナリー型のキー値:

contacts.STREET

contacts.CITY

contacts.STATE

contacts.ZIP

contacts.COUNTRY

contacts.COUNTRY_CODE

dialogs — 簡単に使えるユーザーインターフェイスダイヤログ

 dialogs モジュールは、iOS上でのシンプルなデータ入力のための簡単に使えるGUI(Graphics User Interface)ダイアログを提供します。多くの場合、ui モジュールの先頭に配置します。ui を直接使用するのに比べて自由度は低くなりますが、より簡単に使用でき、多くの場合、数行の短いスクリプトを書くだけで済みます。

概 要

 このモジュールの大部分の関数は、ダイアログを表示し、ユーザーの入力を返します。以下の各種のダイアログをサポートしています:

  • 複数の入力行を持つ文字入力ダイアログ。フォントといくつかのキーボード属性(オートコレクト機能など)をカスタマイズ可能です。(text_dialog() を参照)
  • アイテムのリストから選択するリストダイアログ。アイテムリストの中から一つないし複数を選択できます。(list_dialog() を参照)
  • 同じくアイテムのリストを表示しますが、アイテムのリストを選択するのではなく、ユーザーが順番を変えたり削除したりできる編集リストダイアログ。(edit_list_dialog() を参照)
  • 日付/時刻ダイアログ。日付、時刻またはその双方を選べるデイトピッカーのほか、例えばタイマーに使うようなカウントダウン/継続時間のモードもあります。(date_dialog(), time_dialog(), datetime_dialog(), duration_dialog() を参照)
  • カスタマイズできるデータ入力エリアのリストを持つフォームダイアログ。データ入力エリアにはブール値を得るためのスイッチや、文字列を得るためのテキスト/電子メール/パスワード用エリア、デイトピッカー、複数の選択リストを得るためのチェックマークを配置することができます。このダイアログは一番フレキシブルなタイプのダイアログですが、その一方で多くの項目を設定する必要があります。(see form_dialog() を参照)

ダイアログ関数

dialogs.list_dialog(title='', items=None, multiple=False)

 アイテムのリストを表示し、選ばれたものを返します。ダイアログがキャンセルされた場合には、Noneを返します。

 引数 title にはダイアログの最上段に表示するタイトルを設定します。

 引数 item にはアイテムのリストを設定します。アイテムのリストは文字列に変換できるオブジェクトであればどんな種類のものでも使用可能です。リストとして表示されたどのアイテムでもより簡便に処理できるよう、ディクショナリー型のリストを使うこともできます。

 引数 multiple を True にすれば、複数のアイテムを選択することができます。(詳細は ui.ListDataSource.items を参照)

 

 (例 dialog.list_dialog(title='選んで下さい',items=('選択肢1','選択肢2'),multiple=False) )

dialogs.edit_list_dialog(title='', items=None, move=True, delete=True)

 ユーザーが順番変更をすることが可能なアイテムのリストを表示します。デフォルトでは、リストの中のアイテムの順番を変えるだけでなく、アイテムの削除も可能です。これについては、引数 move と delete で設定できます。

 なお、引数 title にはダイアログの最上段に表示するタイトルを設定します。

 返ってくる値は、修正されたアイテムのリストです。ただし、ダイアログがキャンセルされた場合にはNoneが返されます。

 

 (例 dialogs.edit_list_dialog(title='順序変更や削除が可能です',items=[1,2,3],move=True,delete=True)

dialogs.form_dialog(title='', fields=None, sections=None)

 多くの設定を要するインターフェイスと同様の、フォームダイアログを表示します。

 ダイアログのそれぞれのエリアはディクショナリー型で定義します。エリアが一つしかない場合は、引数 field に設定するディクショナリーを省略することができます。複数のセクションが必要な場合には、タプルで指定します。通常は、セクションのタイトルと、そのエリアのリストの2つのタプルとなります。セクションのフッターの文字を入れる場合には、オプションとして3番目のアイテムとして追加できます。

 この関数の戻り値は、それぞれのフィールドの値のディクショナリー型になります。ただし、ダイアログがキャンセルされた場合には、Noneが返されます。

 

 フィールドを指定するディクショナリーは、以下のキー項目を含む必要があります:

  • 'type' – (必須項目) フィールドのタイプを指定します。'switch', 'text', 'url', 'email', 'password', 'number', 'check', 'datetime', 'date', そして'time'のいずれかにする必要があります。
  • 'key' – フォームからの戻り値の中のフィールドのキーを指定します。
  • 'value' – フィールドの初期値を指定します。text/url/email/password/numberのフィールドの場合は文字列を指定します。 switch フィールドの場合にはブール値(True/False)を、datetimeフィールドの場合には datetime オブジェクトでなければなりません。
  • 'title' – ユーザーが読みやすいように、フィールドにつけるタイトル/ラベルを指定します。

'type' だけが必須のキーです。もし'key' が省略されている場合には、'title' が代わりに使用されます。両方とも無い場合には、戻り値のディクショナリーでは、フィールドに連番が振られることになります。

 

 全てのフィールドタイプにはオプションとして以下のキーが指定できます。

  • 'tint_color' – フィールド上のパーツの色(tint colot)を指定します。指定の効果については、フィールドのタイプにより異なります。
  • 'icon' – システムに組み込まれている画像や ui.Image オブジェクトの名前を指定します。

 text/url/email/password/number のフィールドではオプションとして以下のキーが指定できます:

  • 'placeholder' – フィールドが空の時に表示する文字を指定します。
  • 'autocorrection' – フィールドでの入力に対してオートコレクトを適用するか否かをブール型(True/False)で指定します。
  • 'autocapitalization' – テキスト型のフィールドの場合に自動で大文字化します。どのような値が指定できるかは、 ui.TextField.autocapitalization_type を参照して下さい。
(例)
import dialogs
import datetime

sections = []
fields = []
field = {'type':'switch','key':'chrc1','value':False,'title':'スイッチをスライド→','tint_color':'pink'}
fields.append(field)
sections.append(('Switchだけのセクション', fields))

dt = datetime.datetime.strptime('2021-10-20 20:10:30','%Y-%m-%d %H:%M:%S')
dt2 = datetime.datetime.strptime('2021-10-25','%Y-%m-%d')
fields = [
{'type':'text','key':'chrc2','placeholder':'ここに入力','title':'文字を入力:','tint_color':'yellow'},
{'type':'url','key':'chrc3','value':'https://www.yahoo.co.jp/','title':'URL:','tint_color':'yellow'},
{'type':'email','key':'chrc4','value':'hoge@yahoo.co.jp','title':'E-mail:','tint_color':'linen'},
{'type':'password','key':'chrc5','value':'secret','title':'Password:','tint_color':'linen'},
{'type':'number','key':'chrc6','value':'10','title':'Number','tint_color':'red'},
{'type':'check','key':'chrc7','value':False,'title':'check','tint_color':'purple'},{'type':'datetime','key':'chrc8','value':dt,'title':'datetime:','tint_color':'red'},
{'type':'date','key':'chrc9','value':dt2,'title':'date:','tint_color':'bule'}]
sections.append(('残り全部盛りのセクション', fields))

dialogs.form_dialog(title='全体タイトル',sections=sections)

dialogs.text_dialog(title='', text='', font=('<system>', 16), autocorrection=None, autocapitalization=ui.AUTOCAPITALIZE_SENTENCES, spellchecking=None)

 複数行のテキストを編集できるシートを表示します。

 エディターの挙動は、autocorrection や autocapitalization、spellcheckingparametersで指定できます。引数 text でエディターに最初に表示するテキストを指定します。

 編集されたテキストは、文字列として返されます。なお、ダイアログがキャンセルされた場合には、代わりに None が返されます。

dialogs.date_dialog(title='')

 ディト・ピッカー(日付指定)ダイアログを表示します。戻り値は datetime.datetime オブジェクトです。

dialogs.time_dialog(title='')

 タイム・ピッカー(時刻指定)ダイアログを表示します。戻り値はdatetime.datetime オブジェクトです。

dialogs.datetime_dialog(title='')

 デイト/タイム・ピッカー(日付時刻指定)ダイアログを表示します。戻り値はdatetime.datetime オブジェクトです。

dialogs.duration_dialog(title='')

 カウントダウンタイマーに使われるような残り時間ピッカーを表示します。選択した残り時間を秒単位で返します。(例 1分であれば60.0を返します)

シェア

dialogs.share_image(img)

 引数 img の画像(ui.image と PIL Image のどちらでも可)をシェアするダイアログを表示します。

dialogs.share_text(text)

 引数 text の文字列をシェアするダイアログを表示します。

dialogs.share_url(url)

 引数 URL をシェアするダイアログを表示します。

ファイルのインポート

dialogs.pick_document(types=['public.data'])

 ファイル読込のためのファイル名ピッカー画面を表示し、ユーザーが選択したファイルのパスを返します。ダイアログがキャンセルされた場合にはNone を返します。

 引数 types は、ファイル名ピッカーで選択可能な Universal Type Identifiers(UTIs) で設定する必要があります。デフォルト値として、['public.data'] は全ての一般的なファイル選択が可能なように設定されています。システムで定義された UTIs のリストは、アップルの Uniform Type Identifiers Reference で確認できます。

 戻り値は現在の(テンポラリー)ファイルです。直接読むことができますが、長期にコピーを保存したい場合には、別の場所に移動する必要があります。

警告機能を持つ関数

これらの関数は console モジュールからインポートされています.

dialogs.alert()

 console.alert() を参照

dialogs.input_alert()

 console.input_alert() を参照

dialogs.login_alert()

 console.login_alert() を参照

dialogs.password_alert()

 console.password_alert() を参照

dialogs.hud_alert()

 console.hud_alert() を参照