PhoneGap - Kurzeinführung

Alte vErsion


Wie Phonegap es macht… für jede Plattform wird ein Container mit Webfunktionen geliefert…und eine gemeinsame js Schnittstelle


                                                                     

Voraussetzung
0. Schritt
Eclipse installieren

Installiertes Android Plug Inn & SDK
1. Schritt   SDK herunterladen  und entpacken
Platform
Package
Size
MD5 Checksum
Windows
23449838 bytes
cc2c51a24e2f876e0fa652e182ef5840
Mac OS X (intel)
19871714 bytes
6fcfeed0e1c36624c926551637eb3308
Linux (i386)
16208523 bytes
1d695d6a31310406f5d49092a1bd9850

2. Schritt Eclipse ADT Plug Inn installieren (obsolete seit einiger Zeit)
Über Eclipse Update Site:
https://dl-ssl.google.com/android/eclipse/
3. Schritt in den Prefenrences von Eclipse den Pfad zum Android SDK angeben
4. Schritt Android Virtual Device anlegen

1.     In Eclipse, unter  Window > Android SDK and AVD Manager.
2.      Virtual Devices im Linken Menu – dann  Click New.
3.     Namen und Plattform der  AVD angeben.
4.     Click Create AVD.
Alternativ über Kommandozeile:
android create avd -n my_android1.5 -t 2

Import des Android Projekts in Eclipse
5. Schritt  Version 0.8.0 von PhoneGap laden (Apple approved for App Store submissions)                 
(mirror: tgz | zip) Alternativ GitRepo clonen dort gibt’s ne Version 0.9.0
6. Schritt entpacken
7. Über Eclipse das Android Projekt importieren

Verknüpfung Android– Phonegap  Browser


View wird erzeugt / Programm gestartet
Zu Beginn wird in der Klasse DroidGap die Methode onCreate() aufgerufen. Gespeicherte Sitzungen können dabei übergeben werden.  Zunächst werden allgemeine Parameter gesetzt und danach die R.class verknüpft.


 /** Called when the activity is first created. */

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
      getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
      
// Die Klasse R.class auf die hier Bezug genommen wird,
// wird beim Anlegen eines Projekt mit dem Wizzard erzeugt.

setContentView(R.layout.main);       
        
      appView = (WebView) findViewById(R.id.appView);

 
 





Anschließend wird dem appView die erweiterte PhoneGap Klasse zugewiesen Java Script aktiviert und konfiguriert.


// Set the WebViewClient. Erweiterte PhoneGap Klasse
appView.setWebChromeClient(new GapClient(this));
     
       
appView.getSettings().setJavaScriptEnabled(true);
        appView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);       
               
     
/* Bind the appView object to the gap class methods */
      bindBrowser(appView);
       
 
 







Dem erzeugten/übergebenen View werden JS Funktionen angehängt(bzw. ein Interface). Diese „kommunizieren“ später mit der in der index.html eingebundenen PhoneGap.js Datei.




  private void bindBrowser(WebView appView)
    {

      gap = new PhoneGap(this, appView);
      geo = new GeoBroker(appView, this);
      accel = new AccelListener(this, appView);
      launcher = new CameraLauncher(appView, this);
      // This creates the new javascript interfaces for PhoneGap
      appView.addJavascriptInterface(gap, "DroidGap");
      appView.addJavascriptInterface(geo, "Geo");
      appView.addJavascriptInterface(accel, "Accel");
      appView.addJavascriptInterface(launcher, "GapCam");
    }

 
 


Schließlich wird die Versucht die “Startseite“ zu laden.( bei uns die index.html)


/* Load a URI from the strings.xml file */
Class<R.string> c = R.string.class;

Field f;
       
int i = 0;
       
      try {
        f = c.getField("url");
        i = f.getInt(f);
          this.uri = this.getResources().getString(i);
      } catch (Exception e)
      {
        this.uri = "http://www.phonegap.com";
      }
       appView.loadUrl(this.uri);
       
    }

 
 







       
    












//Ende Klasse DroidGap
}
Beispielhaft die Klasse CameraLauncher mit Konstruktor. Die eine success- und fail- Methode hat. Sowie eine die Methode takePicture() welche die eigentliche Aufnahme in der DroidGap Klasse aufruft. Die Klasse und Methoden können aus der PhoneGap.js heraus angesprochen werden über den oben definierten Namen "GapCam".  

public class CameraLauncher {
           
      private WebView mAppView;
      private DroidGap mGap;
      int quality;     
     
      CameraLauncher(WebView view, DroidGap gap)
      {
            mAppView = view;
            mGap = gap;
      }
     
      public void takePicture(int quality)
      {
            mGap.startCamera(quality);
      }
     
      /* Gibt den Base64 Encoded String zurück ans Javascript */
      public void processPicture( String js_out )
      {          
mAppView.loadUrl("javascript:navigator.camera.win('" + js_out + "');");            
      }
     
      public void failPicture(String err)
      {
mAppView.loadUrl("javascript:navigator.camera.fail('" + err + "');");
      }
     
}

 
 






















Phonegap.js  Was dann die Succes- Funktion dump_pic mit Daten füllt      this.winCallback = successCallback;

Camera.prototype.win = function(picture)
    {
      this.winCallback(picture);
    }

 
 





Auszug Phonegap.js aus z.B.: GWT ansprechbar in die Seite integrierbar successCallback = dump_pic


    Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
   
      this.winCallback = successCallback;
      this.failCallback = errorCallback;
      if (options.quality)
      {
        GapCam.takePicture(options.quality);
      }
      else
      {
        GapCam.takePicture(80);
      }
    }

 

 

Wieder in DroidGap. Aus der CameraLauncher Klassse aufgerufene Methode startCamera(). Eine Aktivity ist eine Art View, zur Interaktion (meistens) mit dem User. Hier wird die Kamera Perpektive aktiviert.

// This is required to start the camera activity!  It has to come from the //previous activity
public void startCamera(int quality)
   {
      Intent i = new Intent(this, CameraPreview.class);
      i.setAction("android.intent.action.PICK");
      i.putExtra("quality", quality);
      startActivityForResult(i, 0);
   }
protected void onActivityResult(int requestCode,                                                          int resultCode, Intent intent)
{     String data;
      super.onActivityResult(requestCode, resultCode, intent);
      if (resultCode == RESULT_OK)
      {
            data = intent.getStringExtra("picture");            
            // Send the graphic back to the class that needs it
// Und leitet sie über den JavaScript weiter an index.html
            launcher.processPicture(data);
      }
      else  {launcher.failPicture("Did not complete!");}
 }

 
Ein Intent ist ne Art Array oder XML Konfigdatei mit besonderer Bedeutung( sie beschreibt die Aktivities und wie mit ihren Ergebnissen umgegangen werden muß- Abstrakte Beschreibung der auszuführenden Operationen). setAction beschreibt, was gemacht werden soll hier eine Auswahl. putExtra gibt den Parameter Fotoqualität an. Außerdem erwartet das ganze ein Ergebnis, welches nachdem es (siehe weiter unter) in der CamerPreview Klasse erzeugt und den Callback Funktionen zugewiesen wurde hier in der onActivityResult weiter verarbeitet wird.


























Beispielhaft mal die Imports. Man sieht hardware, net, View, Activity, …

package com.phonegap.demo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.apache.commons.codec.binary.Base64;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.graphics.Bitmap.CompressFormat;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

 
 



















Zunächst wird wie oben erstmal der View erzeugt, beschrieben, Daten stammen wieder aus der R.Class Datei
SurfaceHolder gibt die Daten indirekt zurück an JS succesCallback

public class CameraPreview extends Activity implements SurfaceHolder.Callback{

    private static final String TAG = "PhoneGapCamera";
    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
   
    Camera mCamera;
    boolean mPreviewRunning = false;
   
    int quality;
    Intent mIntent;
   
    public void onCreate(Bundle icicle)
    {
        super.onCreate(icicle);

        Log.e(TAG, "onCreate");

        getWindow().setFormat(PixelFormat.TRANSLUCENT);

        setContentView(R.layout.preview);
        mSurfaceView = (SurfaceView)findViewById(R.id.surface);
 
 


























Hier wird der callback hinzugefügt. Parameter aus dem übergebenen Intent ausgelesen. ( enthält auch die Callback Funktion). Button und ClickListener


       
mSurfaceHolder = mSurfaceView.getHolder();
      mSurfaceHolder.addCallback(this);
      mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);                   
      mIntent = this.getIntent();
     
      quality = mIntent.getIntExtra("quality", 100);
     
      Button stopButton = (Button) findViewById(R.id.go);
      stopButton.setOnClickListener(mSnapListener);
  }

 
 












  

Hier wird der angehängte callback ausgelöst mCamera.takePicture ist Androids Kameraaufruf


    private OnClickListener mSnapListener = new OnClickListener() {
        public void onClick(View v) {
            mCamera.takePicture(null, null, mPictureCallback);
        }
    };


// Zusaätzliche Funktionen Menu und so

    public boolean onCreateOptionsMenu(android.view.Menu menu) {
        MenuItem item = menu.add(0, 0, 0, "goto gallery");
        item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
            public boolean onMenuItemClick(MenuItem item) {
               Uri target = Uri.parse("content://media/external/images/media");
                Intent intent = new Intent(Intent.ACTION_VIEW, target);
                startActivity(intent);
                return true;
            }
        });
        return true;
    }
   
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
    }

 
 























Wenn Nativ das Foto gemacht wurde…. Hier ist Camera die eigentlich Hardware
 

    /*
     * We got the data, send it back to PhoneGap to be handled and processed.
     *
     */
   
    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        public void onPictureTaken(byte[] data, Camera c) {
            Log.e(TAG, "PICTURE CALLBACK: data.length = " + data.length);
            storeAndExit(data);
        }
    };

 
 


















Hier wird das Result(Foto) ins Intent zurückgegeben putExtra(js_out) und setResult auf OK gesetzt. Löst die Funktion oben aus onActivityResult


    /*
     * We can't just store and exit, because Android freezes up
     * when we try to cram a picture across a process in a Bundle.
     * We HAVE to compress this data and send back the compressed data 
     */
    public void storeAndExit(byte[] data)
    {
      ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
Bitmap myMap = BitmapFactory.decodeByteArray(data, 0, data.length);
            try {
if (myMap.compress(CompressFormat.JPEG, quality, jpeg_data))
                  {
                        byte[] code  = jpeg_data.toByteArray();
                        byte[] output = Base64.encodeBase64(code);
                        String js_out = new String(output);
                        mIntent.putExtra("picture", js_out);
                        setResult(RESULT_OK, mIntent);
                  }    
            }
            catch(Exception e)
            {
                  //Do shit here
            }
        finish();
    }

 
 













































Wenn geklickt wird … mCamera ist Hardware
mPictureCallback  =  Camera.PictureCallback()

    public boolean onKeyDown(int keyCode, KeyEvent event)
    {
        if (keyCode == KeyEvent.KEYCODE_BACK) {           
            return super.onKeyDown(keyCode, event);
        }

    if (keyCode == KeyEvent.KEYCODE_CAMERA
|| keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_SEARCH)
{
        mCamera.takePicture(null, null, mPictureCallback);
        return true;
      }
        return false;
    }

    protected void onResume()
    {
        Log.e(TAG, "onResume");
        super.onResume();
    }

    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
    }

    protected void onStop()
    {
        Log.e(TAG, "onStop");
        super.onStop();
    }

 
 







































Hier die Oberflächen Verarbeitung Camera öffnen, schließen, beenden ( wie bei Datenbankverbindungen)



    public void surfaceCreated(SurfaceHolder holder)
    {
        Log.e(TAG, "surfaceCreated");
        mCamera = Camera.open();
        //mCamera.startPreview();
    }

    public void surfaceChanged(SurfaceHolder holder,
int format, int w, int h)
    {
        Log.e(TAG, "surfaceChanged");

        // XXX stopPreview() will crash if preview is not running
        if (mPreviewRunning) {
            mCamera.stopPreview();
        }

        Camera.Parameters p = mCamera.getParameters();
        p.setPreviewSize(w, h);
        mCamera.setParameters(p);
        try {
                  mCamera.setPreviewDisplay(holder);
            } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
            }
        mCamera.startPreview();
        mPreviewRunning = true;
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
        Log.e(TAG, "surfaceDestroyed");
        mCamera.stopPreview();
        mPreviewRunning = false;
        mCamera.release();
    }

}

 
 









   







 











    function show_pic()
    {
      navigator.camera.getPicture(dump_pic, fail, { quality: 50 });
    }

 
In der index.html wird diese Script Funktion aufgerufen




Mit der Funktion dump_pic

  function dump_pic(data)
    {
      var viewport = document.getElementById('viewport');
      console.log(data);
      viewport.style.display = "";
      viewport.style.position = "absolute";
      viewport.style.top = "10px";
      viewport.style.left = "10px";
      document.getElementById("test_img").src = "data:image/jpeg;base64," + data;
    }

 
 





















“Ablaufdiagram”


Kommentare

Beliebte Posts aus diesem Blog

Ampelschaltung Teil 1 - HTML, CSS und JavaScript Basics

HTML - jquery - mobile - Kontaktformular