Android Barcode Scanning with Renpy

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
spiritprince
Newbie
Posts: 3
Joined: Mon Jun 23, 2014 5:45 am
Contact:

Android Barcode Scanning with Renpy

#1 Post by spiritprince »

Hello Lemmasoft community,

I am trying to integrate barcode scanning ability into Renpy on Android. I would like users to scan barcodes using his or her smartphone during a Renpy game. To do this, I am thinking about importing libraries such as Zxing or Zbar, but my lack of understanding around RAPT makes this approach very difficult to accomplish. An example of such scanning feature in a Renpy game might be a special promotion where a user can scan a physical QR code to unlock content for free. There are many more ways I could think of where such feature could be useful for someone.

So can anyone provide me with some direction on how to go about doing this? Any help would be appreciated!

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Android Barcode Scanning with Renpy

#2 Post by PyTom »

Ren'Py includes pyjinus:

http://pyjnius.readthedocs.org/en/latest/

You can probably drop the barcode library jar in rapt/libs, and then use pyjnius to instantiate objects and call methods. You may also need to edit rapt/templates/AndroidManfiest.xml to add the required uses-permission stanzas, after:

Code: Select all

  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

spiritprince
Newbie
Posts: 3
Joined: Mon Jun 23, 2014 5:45 am
Contact:

Re: Android Barcode Scanning with Renpy

#3 Post by spiritprince »

Okay. I've been working on this all week and I think I'm getting pretty close. I first started coding in java, but I got stuck on registering/creating listeners for scan results. So I switched back to python and used pyjnius to access the necessary Java classes. Here's what I've done so far...

1) Add zxing library jar to rapt/libs
2) Add the following lines to AndroidManifest.xml

Code: Select all

<uses-permission android:name="android.permission.CAMERA"/>

<activity android:name=".CaptureActivity"
              android:screenOrientation="landscape"
              android:clearTaskOnLaunch="true"
              android:stateNotNeeded="true"
              android:windowSoftInputMode="stateAlwaysHidden">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
      <intent-filter>
        <action android:name="com.google.zxing.client.android.SCAN"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
</activity>
3) Then I tried calling the activity via intent using the following code.

Code: Select all

    python:
        from jnius import autoclass

        _activity = autoclass('org.renpy.android.PythonActivity').mActivity
        Intent = autoclass('android.content.Intent')

        intent = Intent('com.google.zxing.client.android.SCAN')
        intent.putExtra('SCAN_MODE', 'QR_CODE_MODE')

         _activity.startActivityForResult(intent, 0)
When I run this code on an Android device, it shoots up a 'Complete action using' window where it lists all my installed applications with zxing built in (there's quite a few). If I select the renpy app, it won't run. But if I select another app, the scanner pops up and I'm able to scan codes. This is the first part I'm stuck on.

4) Now I need a way to setup listeners so when the code gets scanned, the result gets sent back properly. This is what I have so far.

Code: Select all

    python:
        from jnius import PythonJavaClass, java_method, autoclass, cast

        _activity = autoclass('org.renpy.android.PythonActivity').mActivity
        Bundle = autoclass('android.os.Bundle')
        Intent = autoclass('android.content.Intent')
        
        _callbacks = {
            'on_activity_result': [] }

        class ActivityResultListener(PythonJavaClass):
            __javainterfaces__ = ['org/renpy/android/PythonActivity$ActivityResultListener']
            __javacontext__ = 'app'

            def __init__(self, callback):
                super(ActivityResultListener, self).__init__()
                self.callback = callback

            @java_method('(IILandroid/content/Intent;)V')
            def onActivityResult(self, requestCode, resultCode, intent):
                self.callback(requestCode, resultCode, intent)

            @java_method('(Ljava/lang/Object;)Z')
            def equals(self, obj):
                return obj.hashCode() == self.hashCode()

            @java_method('()I')
            def hashCode(self):
                return id(self)

        def bind(**kwargs):
            for event, callback in kwargs.items():
                if event not in _callbacks:
                    raise Exception('Unknown {!r} event'.format(event))
                elif event == 'on_new_intent':
                    listener = NewIntentListener(callback)
                    _activity.registerNewIntentListener(listener)
                    _callbacks[event].append(listener)
                elif event == 'on_activity_result':
                    listener = ActivityResultListener(callback)
                    _activity.registerActivityResultListener(listener)
                    _callbacks[event].append(listener)

        class Scanner(object):
            def onScan(self):
                intent = Intent('com.google.zxing.client.android.SCAN')
                intent.putExtra('SCAN_MODE', 'QR_CODE_MODE')
                bind(on_activity_result=self.on_activity_result)

                _activity.startActivityForResult(intent, 0)
                        
            def on_activity_result(self, requestCode, resultCode, data):
                if requestCode == 0:
                    if resultCode == RESULT_OK:
                        intent = Intent()
                        contents = intent.getStringExtra('SCAN_RESULT')
                        format = intent.getStringExtra('SCAN_RESULT_FORMAT')
If I then run onScan() method on an Android device, I get the following traceback.

Code: Select all

While running game code:
  File "game/script.rpy", line 29, in _init_
  File "jnius_proxy.pxi", line 33, in jnius.jnius.PythonJavaClass._init_(jnius/jnius.c:18519)
  File "jnius_proxy.pxi", line 148, in jnius.jnius.create_proxy_instance (jnius/jnius.c:20279)
  File "/home/tom/ab/android/python-for-android/build/python-install/lib/python2.7/site-packages/jnius/reflect.py", line 149, in autoclass
  File "jnius_export_func.pxi", line 23, in jnius.jnius.find_javaclass (jnius/jnius.c:9271)
 JavaException: Class not found 'org/jnius/NativeInvocationHandler'
This might be a completely wrong way of implementing listeners, but I haven't found another way yet... I don't know how to fix the JavaException error. Are there missing pieces of pyjnius library that needs to be recompiled? Any help would be appreciated.

Thanks!

spiritprince
Newbie
Posts: 3
Joined: Mon Jun 23, 2014 5:45 am
Contact:

Re: Android Barcode Scanning with Renpy

#4 Post by spiritprince »

Nevermind I figured it out. I went back and wrote everything in Java, then I called it using pyjnius. Much easier this way.

Post Reply

Who is online

Users browsing this forum: Google [Bot]