3

I've very nearly finished developing a HTML5 app with Appcelerator, and I have one function left to add which is a function to allow the user to take a photo when sending the client a message through the app. There is a specific div that is displayed which contains the message form, and I'd like the user to be able to take a photo with their phone, and have it automatically attached to the message which is then submitted to our server.

However, after hunting around I'm stumped as to how to get it working. While the API shows the Javascript to make the camera work, I can't seem to access it, and I don't know where the API call should be located. Does it go in the app.js file, or it's own file, or does it not really matter where it's called? Any help/advice would be appreciated on this.

EDIT
Thanks to Dragon, I've made the following changes to my code:

index.html

        <div class="col-square">
            <a href="#" onclick="Ti.App.fireEvent('app:fromWebView');"><i class="fa fa-camera fa-squareBlock"></i><br />Take Photo</a>
        </div>

<script type="text/javascript">
    Ti.App.addEventListener("app:fromTitanium", function(e) {
        alert(e.message);
    });
</script>

app.js

Ti.App.addEventListener('app:fromWebView', function(e){

  Titanium.Media.showCamera({

    success:function(event)
    {       
        var image = event.media;
        var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory,"userImg.jpg");
        file.write(image);
        var data = file.nativePath;

        Ti.App.fireEvent('app:fromTitanium', {message: "photo taken fine"});

    },
    cancel:function()
    {
    },
    error:function(error)
    {
      var a = Titanium.UI.createAlertDialog({title:'Camera'});
      if (error.code == Titanium.Media.NO_CAMERA)
      {
        a.setMessage('Please run this test on device');
      }
      else
      {
        a.setMessage('Unexpected error: ' + error.code);
      }
      a.show();
    },
    showControls:false, // don't show system controls
    mediaTypes:Ti.Media.MEDIA_TYPE_PHOTO,
    autohide:false  // tell the system not to auto-hide and we'll do it ourself
  });
});

However, in this case the the button opens the camera up fine. But, when the photo is taken, and selected, it returns to the screen but nothing happens. It then gives this error in the debug - "Ti is undefined". When I then define Ti, it will return "App is undefined".

The peculiar thing with this is that if I remove the code that will handle data being sent from app.js to the webview, it works fine, even though the code to open the camera from the webview is near enough the same code?

mickburkejnr
  • 3,652
  • 12
  • 76
  • 109

2 Answers2

3

here is what you can do :

Inside your webview call and Event and write the event listener inside the parent of webview. Something like this will go inside webview:

<button onclick="Ti.App.fireEvent('app:fromWebView', { message: 'event fired from WebView, handled in Titanium' });">fromWebView</button>

Followed by something like this inside the parent js of webview :

Ti.App.addEventListener('app:fromWebView', function(e) {
    alert(e.message);
    //Here you can call the camera api.
})

for sending the image to the webview follow the reverse process.

Don't forget to check the Docs.

Hope it helps.

Dragon
  • 719
  • 1
  • 9
  • 18
1

I always avoid having Event Listeners in the 'web' world in Titanium. When you call 'fireEvent' from your webview, you are crossing the bridge from the webview sandbox to the native world. That is where Titanium takes the picture and saves it to the file system. For Titanium to tell the webview it is finished, I recommend evalJS. Much more reliable.

Here is an example using the Photo Gallery instead of the Camera. Much easier to test in a simulator. Just replace Titanium.Media.openPhotoGallery with Titanium.Media.showCamera to use the camera instead.

app.js

var win = Ti.UI.createWindow({
    background : 'white',
    title : 'camera test'
});

var webview = Ti.UI.createWebView({
    url : 'test.html'
});

win.add(webview);
win.open();

Ti.App.addEventListener('choosePicture', function(e) {

    var filename = e.filename;

    Titanium.Media.openPhotoGallery({

        success : function(event) {
            var image = event.media;
            var file = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, filename);
            file.write(image);
            var full_filename = file.nativePath;
            webview.evalJS('photoDone("' + full_filename + '");');

        },
        cancel : function() {
        },
        error : function(error) {
            var a = Titanium.UI.createAlertDialog({
                title : 'Camera'
            });
            if (error.code == Titanium.Media.NO_CAMERA) {
                a.setMessage('Please run this test on device');
            } else {
                a.setMessage('Unexpected error: ' + error.code);
            }
            a.show();
        },
        showControls : false, // don't show system controls
        mediaTypes : Ti.Media.MEDIA_TYPE_PHOTO,
        autohide : true
    });
});

test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>My HTML Page</title>
        <style>
            body {
                padding-top: 20px
            }
        </style>
        <script>
            var photoNumber = 0;
            function doShowCamera() {
                photoNumber++;
                Ti.App.fireEvent('choosePicture', {
                    filename : photoNumber + ".png"
                });
            }

            function photoDone(filename) {
                var img = document.getElementById('myPhoto');
                img.src = filename;
            }

        </script>
    </head>
    <body>
        <img id="myPhoto" width="300" height="400"/>
        <input type="button" value="Show Pictures" onclick="doShowCamera();" />
    </body>
</html>

The Ti.App.addEventListener call can be anywhere in your Titanium code (not in your webviews) as long as it is only run once. app.js is as good a place as any to run it.

Jeff Bonnes
  • 1,128
  • 6
  • 6