Aufgabenstellung
Es wird eine Möglichkeit gesucht eine Android App mit einen PHP Backend kommunizieren zu lassen
Intention
PHP mit MySQL Server erhält man oft schon mit billigem Webspace. Ein weiterer Vorteil eines fertigen Webpacks/Webspace ist, dass es nicht notwendig wird sich um eine Backupstrategie zu kümmern. In den meisten Fällen (SLAs und AGBs des Providers studieren) liegt dieses Problem in den Händen des Providers. Er kümmert sich auch um die Sicherheit des Servers. Bei Hackerattacken ist man nicht in der Verantwortung den Server zu härten und zu schützen. Daher kann der Provider auch keine Schadensersatzansprüche gegen den Kunden geltend machen, wenn ein Server gekapert wird und z.B. mit der Installation eines Botnetzes die Leistungsfähigkeit des Rechenzentrums beeinträchtigt ist.
Ansatz
- Implementierung eines möglichst einfachen Authentifierungsmechanismus in PHP mit MySQL-Anbindung
- Wegkapseln der Serviceaufrufe
- Asynchrone Verarbeitung der JSON Aufrufe per Java Thread
- Reaktion in der MainActivity beim Erhalten des Service-Ergebnisses für UI Manipulationen
Der häufigste Ansatz, den man in Tutorials findet, ist die Kommunikation über JSON, einem kompakten Datenformat in für Mensch und Maschine einfach lesbarer Textform zum Zweck des Datenaustauschs zwischen Anwendungen.
Lösung
BjoernServiceCaller.java – Klasse für weggekapselte Service aufrufe mit CallBack-Funktionalität über onLoginResult
package com.caprisoft.contactupload.services;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import com.caprisoft.contactupload.MainActivity;
import android.content.Context;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
public class BjoernsServiceCaller
{
final String authenticationURL = "authenticationservice.php";
private static BjoernsServiceCaller instance = null;
private BjoernsServiceCaller() {}
/**
* Statische Methode, liefert die einzige Instanz dieser
* Klasse zurück
*/
public static BjoernsServiceCaller getInstance()
{
if (instance == null)
{
instance = new BjoernsServiceCaller();
}
return instance;
}
public void loginUser(final MainActivity ctx,
final String email, final String password)
{
Thread t = new Thread()
{
public void run()
{
//For Preparing Message Pool for the child Thread
Looper.prepare();
HttpClient client = new DefaultHttpClient();
//Timeout Limit
HttpConnectionParams
.setConnectionTimeout(client.getParams(), 10000);
HttpResponse response;
JSONObject json = new JSONObject();
try
{
HttpPost post = new HttpPost(authenticationURL);
json.put("email", email);
json.put("password", password);
StringEntity se = new StringEntity( json.toString());
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,
application/json"));
post.setEntity(se);
response = client.execute(post);
/*Checking response */
if(response!=null)
{
BufferedReader reader = new BufferedReader
(
new InputStreamReader
(
response.getEntity().getContent(), "UTF-8"
)
);
String derText = reader.readLine();
// CallBack aufruf in MainActivity
ctx.onLoginResult(derText);
}
}
catch(Exception e)
{
e.printStackTrace();
}
Looper.loop(); //Loop in the message queue
}
};
t.start();
}
}
authenticationservice.php – Das PHP Backend, was die Datenbankabfragen macht und auf jedem Billigwebspace läuft
<?php
include("configuration/database.php");
$json = file_get_contents('php://input');
$obj = json_decode($json);
$result2=mysql_query("SELECT id, activationcode FROM users ".
"WHERE email='".$obj->{'email'}."' AND ".
"password='".$obj->{'password'}."'")
or die(mysql_error());
$user="nouser";
while ($row = mysql_fetch_array($result2, MYSQL_NUM)) {
$user=$row[0];
$activationcode=$row[1];
}
$posts = array(1);
if($user!="nouser")
{
if($activationcode=="activated")
{
session_start();
session_register("userid");
$_SESSION["userid"] =$user;
header('Content-type: application/json');
echo "success";
}
else
{
$registrationcode=substr(md5($obj->{'email'}." ".$obj->{'password'}),6);
mysql_query("UPDATE users SET activationcode='".$registrationcode.
"' WHERE email='".$obj->{'email'}."'") or die(mysql_error());
mail($obj->{'email'},"Registrationcode for contactupload.com",
"Hello!<br><br>\n You or someone else has registered this email ".
"address via mobile phone.<br><br>\nThe generated registrationcode is ".
$registrationcode.".<br><br>\nPlease type this registrationcode in ".
"the register section of the contact sync app.<br><br> .
"\nWith best regards,<br>\ncontactupload.com");
echo "not activated";
}
}
else
{
echo "not registered";
}
mysql_close($con);
?>
MainActivity.java – Die Klasse präsentiert den Code der Benutzeroberfläche der Activity (VIEW)
package com.caprisoft.contactupload;
import com.caprisoft.contactupload.services.BjoernsServiceCaller;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText email = null;
private EditText passwort = null;
/** Called when the user selects the Send button */
public void onClickLoginButton(View view) {
// Do something in response to button
Log.d(this.getClass().toString(), "Login Button gedrückt!");
BjoernsServiceCaller.
getInstance().
loginUser
(
this,
email.getText().toString(),
passwort.getText().toString()
);
}
/** Called when the user selects the Send button */
public void onClickRegisterButton(View view) {
// Do something in response to button
Log.d(this.getClass().toString(), "Register Button gedrückt!");
}
public void onLoginResult(String text)
{
Toast.makeText(this, "HALLO: "+text, Toast.LENGTH_LONG).show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
email = (EditText) findViewById(R.id.textUsername);
passwort = (EditText) findViewById(R.id.textPassword);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
Activity_main.xml – Das eigentliche Frontend
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/labelUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/labelUsername"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText android:id="@+id/textUsername"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="textNoSuggestions"
android:hint="@string/hintUsername" />
<TextView
android:id="@+id/labelPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/labelPassword"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText android:id="@+id/textPassword"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:inputType="textPassword"
android:hint="@string/hintPassword" />
<Button
android:id="@+id/buttonLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickLoginButton"
android:text="@string/buttonLogin" />
<Button
android:id="@+id/buttonRegister"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClickRegisterButton"
android:text="@string/buttonRegister" />
</LinearLayout>
AndroidManifest.xml – Permission für den Zugriff auf das Internet einrichten
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.caprisoft.contactupload"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>