• mapmangame

    @ccc I'm up for that. I'm pretty weak on objective-c so my code is a little scratchy. I would benefit from someone giving it the once over.

    Do you think I should fork it, or create a branch and merge back in?

    posted in Pythonista read more
  • mapmangame

    Hi Matteo

    Sure, he goes:

    1. The entire game engine was written, tested and debugged in Pythonista on my iPhone. I combined this code with the Pythonista App Template (https://github.com/omz/PythonistaAppTemplate). The app template contains a version of Pythonista as a library which run your python code within Xcode. I had to do a small amount of debugging in Xcode to cope with some small differences between the version of pythonista in the template (which seems a little old) and the latest version of pythonista. I also extended the template a little to accommodate in-app purchases.

    2. Yes you definitely need a mac to upload to the App store. There is no way round this as this is the way apple have designed it. There are ways to distribute python code to other pythonista users by making your code open source. An example is stash (shell for pythonista) see https://github.com/ywangd/stash. Stash is installed by cutting and pasting some simple commands into pythonista.

    3. Pythonista apps are probably always going to be a little bit on the big side. The pythonistakit library itself is 50mb. There is also a feature of the pythonista template which copies your code and files to a writable directory (in case you code needs to change them). This has the effect of roughly doubling the size of your app (this is the documents and data that you allude to). In my case most of the 100Mb is music files as MapMan has about 40minutes of original music, the rest is images and a very small amount is the actual source code. I think a bare bones pythonista yellow world app would be about 50-60mb. The pythonista template itself contains a hello world example.

    4. I think my pure python code is very small i.e. well under 1Mb. The compile pythonistakit is around 50Mb. There are also various python modules that are bundled as standard in the template, but these can be deleted if your app doesn't use them.

    Note also there are a few pitfalls with the template owing to Apple's submission policy, I would in particular flag this discussion on the forum: https://forum.omz-software.com/topic/3744/xcode-template-for-pythonista/25?page=2. I got it working, but it did take a bit of fiddling.



    posted in Pythonista read more
  • mapmangame

    Quick update after two days in the App Store we’ve had 9342 downloads, not bad for a game written on a phone!

    You can see the sales chart here https://m.facebook.com/mapmangame/

    or here


    posted in Pythonista read more
  • mapmangame

    No problem, I will put something together. Maybe a blog or something spelling it out. I’m catching up with a few things after getting the MapMan release out, so it might be a few days.

    In the mean time the outline answer is that I added objective-c code to the template to handle the purchases and then used objects_util calls within my python script to call out the the objective-c code. As the Apple store kit is asynchronous I defined a callback interface within the template which I implemented in the python code. So I could continue to code my app within Pythonista I used dependency injection to switch between the real purchase class (used when my game was launched from the template)
    and dummy purchase class (used when launching within Pythonista). I guess the template could be extended with the code I wrote (it would need a little cleaning up as I have a very poor grasp of objective-c).

    The resorted to the above as I could not get in-App working with just objc_util calls within Pythonista. I think this is down to Apple’s security around in-App purchases which forces them to original from the main thread (but I’m guessing).

    posted in Pythonista read more
  • mapmangame

    Last post on this, I promise!

    MapMan is now available for download in the App Store!

    MapMan is free to download and offers an optional in-app purchase (the fist Pythonista App to do this - as far as I know!).

    For more info on the game please see http://mapmangame.com and my blog telling the storing of how it was developed on my iPhone http://mapmangame.blogspot.co.uk

    It you are on twitter we are @mapmangame and any retweets would be really appreciated.

    Thanks again to the Pythonista Forum for all the help over the last year, this is a really great community!

    Thansk finally to @omz for creating a truly remarkable app and opening up the possibility of developing real iPhone Apps on an iPhone! It's been fun!

    posted in Pythonista read more
  • mapmangame

    Hello, me again!

    MapMan is now available for pre-order on the App Store. If you pre-order now and you all get it as soon as its released on May 4th. It's free with an optional In-App purchase.

    It's great to see it finally showing in the App Store. Thanks again to the Pythonista forum for helping me out many times when developing this!



    posted in Pythonista read more
  • mapmangame


    You could try writing a web app in Flask within pythonista. I believe there are a few tools that let you turn flask apps into standalone desktop apps (although I haven't tried them myself) e.g. https://github.com/Widdershin/flask-desktop

    Maybe someone on the forum has experience of this strategy? I would be interested to try it myself sometime.

    posted in Pythonista read more
  • mapmangame

    Hi Everyone

    Further to my post a copy of weeks back we have set a release date for MapMan for Friday the 4th of May.

    MapMan was coded using Pythonista and built into an App using the Pythonista App Template. It was a really fun project and I really hope it showcases just what's possible with Pythonista.

    You can read more about how MapMan was developed by reading our blog at http://mapmangame.blogspot.co.uk

    We also have a website mapmangame.com, a Facebook page and we are @mapmangame on twitter.
    I'll post again on Friday to announce the release. If you have a few minutes it would be really appreciated if you could download and try out MapMan. It's free to download with an optional in-app purchase.



    posted in Pythonista read more
  • mapmangame

    Sure which doc do you mean?

    posted in Pythonista read more
  • mapmangame

    I have got this working by moving the code that uses storekit into the pythonista template. objc_util calls from within pythonista are used to control the code in the template.

    I think the security around storekit might be conflicting with running the store kit calls from the python interpreter.

    posted in Pythonista read more
  • mapmangame

    well both.

    obj_response.products() is an empty array.

    there are a number of articles out there that explain that an empty array denotes something is wrong.

    posted in Pythonista read more
  • mapmangame

    quick update: I've been having some success shifting the purchase code into the Xcode App Template and then using objc_util to call the purchase code added to the template from within pythonista. I've managed to get the list of products back and I'm moving on to implementing purchases now.

    posted in Pythonista read more
  • mapmangame


    I'm developing an app using pythonista and the pythonista app template. I've hit a snag trying to implement in app purchases using the code below (which is adapted from objective code here https://www.tutorialspoint.com/ios/ios_in_app_purchase.htm).

    The issue is that the receive_products method, which does get called-back, is returned an empty list of products. I have checked the itunes connect set up and it seems fine.

    To investigate the issue further I added some objectives code to the pythonista app template and managed to successfully return the correct list of products. This is not useful in practice as I want the user to be able to buy the products after the main.py python script has been started.

    I therefore think the issue relates to threads i.e. I that that store kit probably needs the code to run on the main thread, but I'm not sure. I've tried adding the @on_main_thread decorator, but it's not working.

    Does anyone have any suggestions? Any help really appreciated (as always)

    from objc_util import *
    import ctypes
    import time
    def fetchAvailableProducts(_self, _cmd):
        obj = ObjCInstance(_self)
        sk_class = ObjCClass("SKProductsRequest")
        InApp.Instance.products_request = sk_class.alloc().init(productIdentifiers=ns(InApp.PRODUCTS))
        InApp.Instance.products_request.delegate = obj
    def productsRequest_didReceiveResponse_(_self, _cmd, request, response):
        #defined here: https://developer.apple.com/documentation/storekit/skproductsrequestdelegate/1506070-productsrequest
    def paymentQueue_updatedTransactions_(_self, _cmd, queue, transactions):
        InApp.Instance.update_transactions(queue, transactions)
    class Product:
        def __init__(self, identifier, title, description, price):
            self.identifier = identifier
            self.title = title
            self.description = description
            self.price = price
    class InApp:
        PRODUCTS = ['com.YYY.ZZZ']
        Instance = None
        def initialize(cls):
            cls.Instance = InApp()
        def initialize_dummy(cls):
            cls.Instance = InAppDummy()
        def log(self, message):
        def update_successfull_purchase(self, product_identifier):
            for observer in self.observers:
        def update_failed_purchase(self, product_identifier):
            for observer in self.observers:
        def update_restored_purchase(self, product_identifier):
            for observer in self.observers:
        def get_valid_product(self, product_identifier):
            for product in self.valid_products:
                if product.product_identifier == product_identifier:
                    return product
            raise Exception('Product is not valid: {0}'.format(product_identifier))
        def is_valid_product(self, product_identifier):
            for product in self.valid_products:
                if product.product_identifier == product_identifier:
                    return True
            return False
        def purchase(self, product_identifier):
            if not self.can_make_purchases:
                raise Exception('Purchases are disabled')
                product = self.get_valid_product(product_identifier)
                sk_payment_class = ObjCClass("SKPayment")
                payment = sk_payment_class.alloc().init(product=product)
                default_queue = ObjCClass("SKPaymentQueue").defaultQueue
        def update_transactions(self, queue, transactions):
            for transaction in ObjCInstance(transactions):
                transaction_state = transaction.transactionState
                if transaction_state == "SKPaymentTransactionStatePurchasing":
                elif transaction_state == "SKPaymentTransactionStatePurchased":
                    if transaction.payment.productIdentifier in InApp.PRODUCTS:
                        default_queue = ObjCClass("SKPaymentQueue").defaultQueue
                elif transaction_state == "SKPaymentTransactionStateRestored":
                    default_queue = ObjCClass("SKPaymentQueue").defaultQueue
                elif transaction_state == "SKPaymentTransactionStateFailed":
        def receive_products(self, response):
            self.products_validated = True
            self.valid_products = []
            self.invalid_products = []
            obj_response = ObjCInstance(response)
            valid_products = ObjCInstance(obj_response.products())
            self.valid_count = len(valid_products)
            for valid_product in valid_products:
                print valid_product.productIdentifier
                if (valid_product.productIdentifier in InApp.PRODUCTS):
                    product = Product(valid_product.productIdentifier,
            for invalid in obj_response.invalidProductIdentifiers():
        def __init__(self):
            self.products_request = None
            self.observers = []
            self.log = []
            self.products = []
            self.products_validated = False
            self.valid_count = 0
            self.invalid_products = []
        def add_observer(self, observer):
        def fetch(self):
            superclass = ObjCClass("NSObject")
            methods = [fetchAvailableProducts,
            protocols = ['SKProductsRequestDelegate', 'SKPaymentTransactionObserver']
            purchase_controller_class = create_objc_class('PurchaseController', superclass, methods=methods, protocols=protocols)
            self.purchase_controller = purchase_controller_class.alloc().init()
        def check_purchases_enabled(self):
            sk_payment_queue_class = ObjCClass("SKPaymentQueue")
            self.can_make_purchases = sk_payment_queue_class.canMakePayments()

    posted in Pythonista read more
Internal error.

Oops! Looks like something went wrong!