PAGE TOP


Android WEBサーバーと連動するノートアプリを作る (PhoneGap)

2017年6月28日Android

実装概要

PhoneGapフレームワークを利用して、androidアプリを製作します。機能としては、ブログのように、タイトル、内容を記入して、送信し、それらが反映されるというシンプルなものです。データベースは、サーバーにあるMySQLを利用します。また、フレームワーク内では、PHPは使えませんので、処理は、サーバーで行い、クライアント側のブラウザでは、jQueryのajax()でPOST送信することで、データを送信し、処理内容を受け取るようにします。PhoneGepの環境構築には、Node.js等の準備が必要で、初めての場合は、前回投稿した、Androidアプリ開発 PhoneGapによる開発環境と実機での実行のメモを参考程度に、ご覧ください。あくまで、起動確認のサンプルのような形で作成しましたので、セキュリティー対策が不備であったり、div idが数値になっていたり、突っ込みどころはあると思いますが、こういう感じというイメージで参考程度にご覧ください。

今回は、PhoneGapフレームワーク上で編集するのは、index.htmlだけです。その他のファイルは、サーバーに設置して、index.htmlとajax通信でデータのやり取りを行います。(起動の確認の為、サーバーにindex.htmlを置いてもPCブラウザより確認できます。)

・サンプルのサーバー側のファイル構成

データベースの準備

まずは、フォームからのデータを登録するデータベースを作る必要があります。

postテーブル

CREATE TABLE post (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
title varchar(30) NOT NULL,
content text NOT NULL,
date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

データベースの準備が完了したら、db.phpにMySQLに接続情報を記載します。それをあとで読み込んで使うようにします。(このあたりは、host dbname $user $password の部分は、環境にあわせて、変更してください。)

【db.php】

<?php
 
function db_connect(){
	$dsn = 'mysql:host=localhost;dbname=sample;charset=utf8';
	$user = 'root';
	$password = 'japan';
	
	try{
		$dbh = new PDO($dsn, $user, $password);
		return $dbh;
	}catch (PDOException $e){
	    	print('Error:'.$e->getMessage());
	    	die();
	}
}
 
?>

index.htmlの解説

index.htmlでは、javascriptによるサーバーに置いたファイルとの通信になります。まず、スクリプト部分の解説を上から順に解説します。

data_select.phpより、既にあるデータ一覧を読み込み、それらをdiv id=”all” の部分に入れる。

    $.get('http://sample.com/data_select.php', function (data) {
        $('#all').html(data);    
    });

・[ノートを作る]ボタンの処理
ボタンを押すと、外部のdata_insert.phpにPOSTデータが送信され、データベースに1件のデータが追加される。その後、追加されたデータの1件を取得し、

の部分に追加する。


  $('#post').click(function(){

     if ($('button').hasClass('upd')) {
       alert('その他のページの編集が完了していません。');
     }else if( $('#title').val() === '' || $('#content').val() === '' ) {
       alert('空白箇所があります。');
     }else{
       var title = $("#title").val();
       var content = $("#content").val();

     $.ajax({
        url: 'http://sample.com/data_insert.php',
        type: 'POST',
        data: { 'title': title, 'content': content},
        timeout: 10000,
        dataType: 'text'
        }).done(function( data ) {
        $('#title').val('');
        $('#content').val('');
        $('#all').append(data);
        });
      }
  });

1件分のデータには、それぞれidがつけられています。それらのidに応じて、その部分の削除や編集が行われます。

・[削除]ボタンの処理を押すと、外部のdata_delete.phpに削除する部分のidが送信され、その部分が削除されます。
・[編集]ボタンを押すと、外部のdata_edit.phpより編集フォームを読み込みます。
・[更新]ボタンは、data_edit.phpのフォームを読み込んだ時に表示されるボタンですが、このボタンを押すと、外部のdata_update.phpに更新データが送信され、データベースのデータが更新されます。

  $('#all').on('click','button.del',function(){

       var id = $(this).parent().parent().attr("id"); 
       var req = window.confirm('No.' + id +' 本当にこのページを削除しますか?')
       if (req==true) { 
       $.ajax({
        url: 'http://sample.com/data_delete.php',
        type: 'POST',
        data:{ id:id },
        timeout: 10000,
        dataType: 'text'
        }).done(function( data ) {
        $('#' + id).replaceWith('');
        });
        }else{
        }

  }).on('click','button.edt',function(){

     if ($('button').hasClass('upd')) {
       alert('その他のページの編集が完了していません。');
     }else{
       var id = $(this).parent().parent().attr("id"); 

       $.ajax({
        url: 'http://www.sample.com/data_edit.php',
        type: 'POST',
        data:{ id:id },
        timeout: 10000,
        dataType: 'text'
        }).done(function( data ) {
        $('#' + id).replaceWith(data);
        });
    }

  }).on('click','button.upd',function(){

      if( $('.title').val() === '' || $('.content').val() === '' ) {
       alert('空白箇所があります。');
          }else{

       var title = $(".title").val()
       var content = $(".content").val()
       var id = $(this).parent().attr("id");

           $.ajax({
        url: 'http://sample.com/data_update.php',
        type: 'POST',
        data: { title: title, content: content, id: id},
        timeout: 10000,
        dataType: 'text'
        }).done(function( data ) {
        $('#' + id).replaceWith(data)
        });
            }
  });

html部分は、下記のようになっており、非常に少なく、要は、追加するフォームと、表示する

があるだけです。これをみても分かるように、ほとんどがjavascriptの操作になります。

    タイトル: <input id="title"><br>
    内容: <textarea id="content" rows="3"></textarea><br>
    <button id="post">ページを作る</button>
 
   <div id="all"></div>

サーバー設置のPHPファイル

サーバーに設置した、phpファイルは、phonegape上のindex.htmlに書かれているjavascriptの命令によって、処理が開始されます。もともとデータベースにあるデータ一覧をindex.htmlに読み込んだり、index.htmlより、受け取った、POSTデータをもとに、データベースへの登録・削除・更新をおこない、それらの結果をhtmlとして、index.htmlに書き換えたりします。

【data_select.php】
… index.htmlのjQueryの.get()メソッドで取得される一覧データです。

<?php

require_once("db.php");
$dbh = db_connect();

try{
   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = "SELECT * FROM post";
   $stmt = $dbh->query($sql);
   $data = $stmt->fetchAll();
   
}catch (PDOException $e){
   print('Error:'.$e->getMessage());
   die();
}

foreach ($data as &$val) {
    echo '<div id="'. $val['id'] .'"><h3>' .$val['title'] . '</h3><p>' .$val['date']. ' ' . $val['content']. '<button class="del ui-btn ui-icon-delete ui-btn-icon-left">削除</button><button class="edt ui-btn ui-icon-edit ui-btn-icon-left">編集</button></p></div>' ;
}

?>

【data_insert.php】
… index.htmlの[ノートを作る]ボタンを押したときに、ajax()メソッドを使って、POSTされるデータを受け取り、そのデータを元に、追加した1件分のデータを取得し、index.htmlに返します。

<?php

require_once("db.php");
$dbh = db_connect();

try{
   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = "INSERT INTO post (title,content) VALUES(:title, :content)";
   $stmt = $dbh->prepare($sql);
   $stmt->bindValue(':title', $_POST['title']);
   $stmt->bindValue(':content', $_POST['content']);
      $stmt->execute();

      $pid = $dbh->lastInsertId();       
      $sql = "SELECT * FROM post WHERE id = :id";
      $stmt = $dbh->prepare($sql);
      $stmt->bindValue(':id', $pid);
      $stmt->execute(); 
      $data = $stmt->fetch(PDO::FETCH_ASSOC);

}catch (PDOException $e){
   print('Error:'.$e->getMessage());
   die();
}

?>

<div id="<?=$data['id']?>">

<h3><?=$data['title']?></h3><p><?=$data['date']?><?=$data['content']?><button class="del ui-btn ui-icon-delete ui-btn-icon-left">削除</button><button class="edt ui-btn ui-icon-edit ui-btn-icon-left">編集</button></p>

</div>

【data_delete.php】
… index.htmlより、削除する部分のidを受け取り、それを元に、削除を行います。

<?php

require_once("db.php");
$dbh = db_connect();

try{
   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = "DELETE FROM post WHERE id = :id";
   $stmt = $dbh->prepare($sql);
   $stmt->bindValue(':id', $_POST['id']);
   $stmt->execute();
   
}catch (PDOException $e){
   print('Error:'.$e->getMessage());
   die();
}


?>

【data_edit.php】
… index.htmlのそれぞれの[編集]ボタンを押した際に、その部分のidが.ajax()メソッドを通じて、POSTデータとして渡ってきます。それをもとに、その部分のデータをフォームに設置したhtmlデータをindex.htmlに返します。

<?php

require_once("db.php");
$dbh = db_connect();

try{
   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = "SELECT * FROM post WHERE id = :id";
   $stmt = $dbh->prepare($sql);
   $stmt->bindValue(':id', $_POST['id']);
   $stmt->execute();
   $data = $stmt->fetch(PDO::FETCH_ASSOC);   

}catch (PDOException $e){
   print('Error:'.$e->getMessage());
   die();
}

?>


<div id="<?=$data['id'] ?>">

  件名: <input class="title" value="<?=$data['title'] ?>"><br>
    本文: <textarea class="content" rows="3" ><?=$data['content'] ?></textarea><br>
    <button class="upd ui-btn ui-icon-edit ui-btn-icon-left">更新</button>
</div>


【data_update.php】
… data_edit.phpより読み込まれたフォームにある[更新]ボタンを押したときに、その部分のidが、.ajax()メソッド
通じてわたってきますが、そのデータを更新します。その後、更新後の1件分のデータを取得して、index.htmlに返します。

<?php

require_once("db.php");
$dbh = db_connect();

try{
      $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $sql = "UPDATE post SET title = :title, content =:content WHERE id =:id";
      $stmt = $dbh->prepare($sql);
      $stmt->bindValue(':title',$_POST['title']);
      $stmt->bindValue(':content',$_POST['content']);
      $stmt->bindValue(':id',$_POST['id']);
      $stmt->execute();
  
      $sql = "SELECT * FROM post WHERE id = :id";
      $stmt = $dbh->prepare($sql);
      $stmt->bindValue(':id', $_POST['id']);
      $stmt->execute(); 
      $data = $stmt->fetch(PDO::FETCH_ASSOC);


}catch (PDOException $e){
   print('Error:'.$e->getMessage());
   die();
}

?>

<div id="<?=$data['id'] ?>">

<h3><?=$data['title'] ?></h3><p><?=$data['date'] ?><?=$data['content'] ?><button class="del ui-btn ui-icon-delete ui-btn-icon-left">削除</button><button class="edt ui-btn ui-icon-edit ui-btn-icon-left">編集</button></p>

</div>

【追加 2018.3.1】
サンプルのシュミレーターでは、ブラウザによっては、クロスドメイン制約で非同期時に指定したURLに通信できない可能性があります。そこで、それを回避するために、読み込む側のPHPファイルの頭に、header(“Access-Control-Allow-Origin: *”);を追加して、通信許可してください。

感想

PhoneGapフレームワークを使うと、javascriptの知識で、アプリが作れるのが便利なところです。また、デバックは、androidでやっていますが、iOSでも起動できるので、これがハイブリットアプリの良いところです。

それとコードを書いていて、ビルドして気づいたことですが、スマフォ上では、jqeruyの.load()メソッドが動いていないことに気づきました。stackoverflowに 「Will jQuery .load() Work On PhoneGap?」記事があり、フレームワークの仕様によるものなので、記事にあるように.get()に変更しました。

  //$("#all").load("http://sample.com/data_select.php");

    $.get('http://sample.com/data_select.php', function (data) {
        $('#all').html(data);    
    });

おそらく、こういうのはまだ他にもあると思います。
それと記事にまとめる際に、アプリのビルドについては書いてないのですが、このあたりは前回のAndroidアプリ開発 PhoneGapによる開発環境と実機での実行のメモを参考ください。