kivy-iosメモ kivy v1.8.0 URL連携（MAC）


#Deprecated this article (Reference to [New article](http://qiita.com/leon_AKQJT/items/f73adb4205fef5512dc4))

　iOSでURL連携を行うには、どのように行えば良いかを調べました。kivy-ios内にメールAPPとの連携の部分があったのでそれを参考に実装することができます。

### 1.呼び出し編

```py:インポート／前処理
try:
    from urllib.parse import quote
except ImportError:
    from urllib import quote
from pyobjus import autoclass, objc_str
from pyobjus.dylib_manager import load_framework

load_framework('/System/Library/Frameworks/UIKit.framework')

NSURL = autoclass('NSURL')
NSString = autoclass('NSString')
UIApplication = autoclass('UIApplication')
```
```py:呼び出し（メール）
uri = "mailto:mail@dom.com?subject=text&body=body"
nsurl = NSURL.alloc().initWithString_(objc_str(uri))
UIApplication.sharedApplication().openURL_(nsurl)
```

### 2.呼び出され編


　[参考サイト](http://develop.calmscape.net/dev/232/)を参考にして、XCodeでurlschemeを定義します。これで、他のアプリケーションから呼び出されるようになりますが、ほとんどのアプリケーションは引数を受け取りたいと思うはずです。しかし、kivy-iosでは標準では引数を受け取れないようで、なんらかの仕組みで受け取る必要があります。kivyでは、ドロップファイルのイベントを生成する時にiOSのopenUrlのイベントを受け取るようになっています。しかし、これはアプリケーションまで、イベントが伝わってないため受け取れません。新規でイベントを追加するよりもこれを流用した方が簡単なので流用します。修正場所は、kivy-iosディレクトリのtmpの下です。

・kivy内のCython用のSDLイベント定義にドロップファイルのインターフェースを追加します。

```py:kivy/kivy/core/window/sdl.pyx
        .
        .
        .
    ctypedef struct SDL_TouchFingerEvent:
        long touchId
        long fingerId
        unsigned char state
        unsigned short x
        unsigned short y
        short dx
        short dy
        unsigned short pressure

    # add start
    ctypedef struct SDL_DropEvent:
        unsigned int timestamp
        char *file
    # add end

    ctypedef struct SDL_Event:
        unsigned int type
        SDL_MouseMotionEvent motion
        SDL_MouseButtonEvent button
        SDL_WindowEvent window
        SDL_KeyboardEvent key
        SDL_TextInputEvent text
        SDL_TouchFingerEvent tfinger
    # add start
        SDL_DropEvent drop
    # add end 

    # Events
    int SDL_QUIT
    int SDL_WINDOWEVENT
    int SDL_SYSWMEVENT
    int SDL_KEYDOWN
    int SDL_KEYUP
    int SDL_MOUSEMOTION
    int SDL_MOUSEBUTTONDOWN
    int SDL_MOUSEBUTTONUP
    int SDL_TEXTINPUT
    int SDL_FINGERDOWN
    int SDL_FINGERUP
    int SDL_FINGERMOTION
    # add start
    int SDL_DROPFILE
    # add end                
        .
        .
        .
    elif event.type == SDL_TEXTINPUT:
        s = PyUnicode_FromString(<char *>event.text.text)
        return ('textinput', s)
    # add start
    elif event.type == SDL_DROPFILE:
        s = PyUnicode_FromString(<char *>event.drop.file)
        action = ('dropfile', s)
        return action
    # add end
    else:
        if __debug__:
            print('receive unknown sdl event', event.type)
        pass
        .
        .
        .
```

・SDLのラッパーの部分で上記イベントを捕捉できるようにします。

```py:kivy/kivy/core/window/window_sdl.py
        .
        .
        .
    def _mainloop(self):
        EventLoop.idle()

        while True:
            event = sdl.poll()
        .
        .
        .
            elif action == 'textinput':
                key = args[0][0]
                # XXX on IOS, keydown/up don't send unicode anymore.
                # With latest sdl, the text is sent over textinput
                # Right now, redo keydown/up, but we need to seperate both call
                # too. (and adapt on_key_* API.)
                self.dispatch('on_key_down', key, None, args[0],
                              self.modifiers)
                self.dispatch('on_keyboard', None, None, args[0],
                              self.modifiers)
                self.dispatch('on_key_up', key, None, args[0],
                              self.modifiers)
            # add start
            elif action == 'dropfile':
                self.dispatch('on_dropfile', args[0])
            # add end

        #    # video resize
        #    elif event.type == pygame.VIDEORESIZE:
        .
        .
        .
       # XXX FIXME wait for sdl resume
        while True:
            event = sdl.poll()
            if event is False:
                continue
            if event is None:
                continue

            action, args = event[0], event[1:]
            if action == 'quit':
                EventLoop.quit = True
                self.close()
                break
            elif action == 'windowrestored':
                break
            # add start
            elif action == 'dropfile':
                app.dispatch('on_dropfile', args[0])
            # add end
        .
        .
        .
```

・メイン関数で受け取れるようにドロップファイルのイベントインターフェースを追加します。


```py:kivy/kivy/app.py
        .
        .
        .
    # Return the current running App instance
    _running_app = None

    # modify start ( add on_dropfile )
    __events__ = ('on_start', 'on_stop', 'on_pause', 'on_resume', 'on_dropfile')
    # modify end

    def __init__(self, **kwargs):
        App._running_app = self
        self._app_directory = None
        self._app_name = None
        .
        .
        .
    def on_resume(self):
        '''Event handler called when your application is resuming from
        the Pause mode.

        .. versionadded:: 1.1.0

        .. warning::

            When resuming, the OpenGL Context might have been damaged / freed.
            This is where you can reconstruct some of your OpenGL state
            e.g. FBO content.
        '''
        pass

    # add start
    def on_dropfile(self, filename):
        '''Event called when a file is dropped on the application.

        .. warning::

            This event is currently used only on MacOSX with a patched version
            of pygame, but is left in place for further evolution (ios,
            android etc.)

        .. versionadded:: 1.2.0
        '''
        pass
    # add end

    @staticmethod
    def get_running_app():
        .
        .
        .
```

・Tools/Build-all.shを実行後、自分のメイン関数に def on_dropfile(self, filename): を定義すると、イベントとして取得可能となります。注意点としてはURLエンコードされているので、取得後にURLデコードを行う必要があります（[URLデコード参考](http://foreignkey.jp/archives/171)）。

```py:main.py
        .
        .
        .
    def on_dropfile(self, filename):     <---- ここで、URL連携で呼び出された引数を取得可能になる。
        print self.mydecode(filename)

    def mydecode(self, value):
        if isinstance(value, unicode):
            value = value.encode('raw_unicode_escape')
        value = urllib.unquote(value)
        return value

if __name__ == '__main__':
    TestApp().run()
```

※kivy-iosで連携が可能となりますが、このやり方は製作者の意図しない方法ですのでバージョンアップの際には使用できなくなる可能性がありますので、留意が必要です。