Androidの最近のブログ記事

う~ん・・・

Android 標準ブラウザで「文章の選択」を禁止できない。文章をコピー出来ないようにしたいんだけど、「選択」が出来るので、それをコピーしたり保存したり出来ちゃう。

お客さんから相談を受けて色々調べたんだけど、昔の WebKit 版の標準ブラウザならスタイルの設定などで禁止できるんだけど、Blink 版が兎に角どうにもならない。

body のスタイル設定に、

user-select: none;
-webkit-touch-callout:none;
-webkit-user-select:none;
-moz-user-select: none;
-khtml-user-select: none;

と指定しても駄目だし、直接 body タグに

<body 
onSelectStart="return false;" 
onMouseDown="return false;"
ontouchend="return false;"
style="-moz-user-select:none;
-webkit-user-select:none;
-khtml-user-select:none;
user-select:none;">

みたいに書いてみたけど、やっぱり駄目だった。
Blink の指定の仕方があるんだろうな。

-blink-user-select:none; とか?

ググってみたけど違うようだな(^^;

一番有効なのは、文書の上に透過GIF(透明GIF)を置いちゃうこと。そうしとけば、タップしても透過GIFがアクティブになるだけで、下の文章には到達できない・・・んだけど、最初からそういう前提でデザインにしてないので、簡単にはいかないんだよね。
それに、これやっちゃうと、当然文章の途中にあるリンクなんかも無効になっちゃう。不味いよねぇ。

JavaScript で何とか出来るんじゃね?とも思ったんだが、Blink 版じゃ onSelectStart 等のイベントが JavaScript で取れなくて何もできなかった。

う~ん・・・現状では Blink 版標準ブラウザじゃコピー制限は無理?

「馬鹿だなあ、お前。こんな簡単な方法があるんだぜ」という男前な識者からのご指導、お待ちしております!!(笑)
20130830_android.JPG
いやあ、この間まで、風呂場で防水のMP3プレーヤーで音楽再生するだけでも十分だと思ってたのに、最近は Android タブレット(ASUS EeePad Transformer TF101)を Ziploc のストックバッグ(大)に入れて風呂場に持ち込み動画を楽しんでますよ。
まあ、けっこうこういうことしてる人多いみたいだけど。

iPhone はちゃんとした(カヌーに乗るので)防水ケース持ってるんだけど、iPhone の画面じゃあまりに小さいのでねえ・・・あんま動画観る気には・・・(^^;

TF101 は Android タブレットの中でも大きい方なので、ストックバッグの大きいヤツ(273mmx268mm)でもギリギリ収まるくらい。横方向はもうパッツンパッツン(^^;
なので、持った時に Ziploc でサイドについてる電源ボタンが押されて画面が消えちゃうことがあって若干焦る(^^;

でも、まあ、その他には今のところ問題無し。
上記のように横方向にパッツンパッツンなので、ダブルジッパーの内側は外れてしまうこと多し。でも、外側のジッパーはがっちり噛んでいるので、使用中に自然に口が開いて内部に湿った空気が流れ込んで TF101 故障・・・ということは無さそう。

あ、いや、問題はあったわ。
それは、娘と風呂に入った時は使えないってこと。
いやあ、うちの娘、大きな音が嫌いで、風呂の中で音楽なんかを流すの、ホントいやがるんだよね(^^;
動画見てたら、絶対ぶーぶー文句言うわ。落ち着いて観れません(^^;
PhoneGap という、クロスプラットフォーム・モバイルアプリケーション開発フレームワークを使って Android アプリケーション作る手順。

  1. Eclipse で Android アプリの新プロジェクト作成。
  2. PhoneGap ディレクトリ\lib\android\cordova-2.7.0.jar を、プロジェクトの libs 以下にコピー(2.7.0 の部分は、使用する PhoneGap のバージョンによって異なる)
  3. プロジェクトの assets フォルダの下に www というフォルダを作成。
  4. 作成した www フォルダ以下に、PhoneGap ディレクトリ\lib\android\cordova-2.7.0.js をコピー。
  5. プロジェクトの res ディレクトリ以下に、PhoneGap ディレクトリ\lib\android\xml フォルダをコピー。
  6. プロジェクトの src フォルダ内に MainActivity.java が作成されているので、ソースコードを 4箇所修正する。
  7. プロジェクトの AndroidManifest.xml を修正(2箇所)
  8. プロジェクトの assets/www フォルダの下に、HTMLファイル(取り敢えず index.html)を作成する。

MainActivity.java の修正はこんな感じ(修正前の行もコメントにして残してある)

import android.os.Bundle;
//import android.app.Activity;
import org.apache.cordova.DroidGap;
import android.view.Menu;

//public class MainActivity extends Activity {
public class MainActivity extends DroidGap {

@Override
//protected void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
super.loadUrl("file:///android_asset/www/index.html");
}

AndroidManifest.xml の修正はこんな感じ。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.netandfield.denshibooq"
    android:versionCode="1"
    android:versionName="1.0"
    android:windowSoftInputMode="adjustPan" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"

※ともに、太字のところが修正点。

あとは、index.html を始めとし、HTML5 と JavaScript でアプリを作っていくだけ。
以前、Adobe Flash Builder では、自宅用と職場用を買って、それぞれの PC から Dropbox 上に作ったワークスペースを共有して、つまり、会社で作ったプログラムを、自宅に帰ってから修正して実行してみる・・・なんてことをしていたわけだが・・・
(ちなみに、Flash Builder も Eclipse ベースの IDE である)

Android 用のプロジェクトじゃそういうこと出来んの?

会社の ADT bundle Eclipse で作成した Android アプリを、自宅の ADT bundle Eclipse(バージョンは同じだが、会社は 64bit版、自宅は 32bit版)でビルドしようとしたら「ソースが見つからない」とかエラーが出て実行出来ず・・・

会社で、Android SDK のバージョン上げたら同じようなことになってしまったけど・・・

やっぱ、32bit版と 64bit版ではワークスペース、というかプロジェクトを共有することって出来んのかね。
まあ、一からプロジェクト作り直して、ソースをコピーしてやれば問題なく動くんだけど・・・

Subversion とか使ってソースの共有せいという話なんかなあ。

自分独り、会社と自宅でソース共有したいだけなのに、ちょっと不便だな(^^;
ADT バンドル版 Eclise でも ASUS TF101 が認識しなくなっていた問題は、

・最新の ASUS Sync 及び USB Driver をアンインストール
・古い ASUS Sync 及び USB Driver をインストール

で、OKになった。

20130520_ADT_OK.jpg
具体的には、2013年 1月 4日更新の最新版(ASUS Pad PC Suite (PC version V1.0.42))では駄目で、それをアンインストールし、昔の(2011年12月12日に入手)USB Driver に入れ替えたら ADT でもまた認識するようになったということ。

う~ん・・・ASUS Tek も最近なんか信用できんなあ・・・
昔は、良いマザーボード作ってたんだけどねえ。

ちなみに、最新ドライバでも、古いドライバでも、どちらでも ASUS Sync は TF101 を見つけられない様子(^^;(「デバイスが見つかりません」と表示)

なんだかなあ(^^;

<追記>
PC側の ASUS Sync が TF101 を見つけられなかったのは、TF101 側で ASUS Sync を起動させてなかったからだった(^^;
すまんご。
いやあ、もう、なんかめちゃくちゃですよ・・・(^^;
Android 開発環境、色々面倒くせえって言うのはホントだね(^^;

ある Android 開発の入門書には、「開発環境をアップデートして動作しなくなった場合」の回答として、「開発環境を1から作りなおしてください」とか書いてあるからな(^^;

今日の状況。

取り敢えずキャッシュやレジストリをクリアしてみようと思って、"eclipse -clean" で Eclipse を実行。

20130517_ADT_ERROR1.jpg
起動すると、「Please update ADT to the latest version.」と言われるので、最新バージョンを検索。

20130517_ADT_ERROR2.jpg
更新は検出されなかった様子。

で、今まで動いていたプログラムを実行しようとすると、何故か内部エラー発生。
「java.lang.NullPointerException」だって。

20130517_ADT_ERROR3.jpg
SDK Manager 開こうとすれば「設定で Android SDK のロケーションが設定されていません。」のエラー。

20130517_ADT_ERROR4.jpg
でも「設定」を見てみたら、正しい場所が指定されているし・・・(「Please update ADT to the latest version.」エラーは相変わらず出てるが・・・)

20130517_ADT_ERROR5.jpg
わけわから~ん!!

はい。素直に ADT バンドル版 Eclipse を再インストールします・・・とほほ・・・
Adobe Flash Builder 4.6(x86) で、TF101 がプログラム実行可能なデバイスとして認識されない。

20130516_fb_device_none.jpg
「更新」ボタンを押すと、時々変なデバイスが表示される(シリアル番号に「asus-tf101」が表示されず、全然別のシリアル番号が表示される)のだが、そのデバイスを使おうとすると、

アプリケーションのインストール中にエラーが発生しました:
adb server is out of data. killing...

ADB server didn't ACK

* faild to start daemon *

error:

という内容のダイヤログが開き失敗。

むーん・・・

でも、ADT bundle 版の Eclipse からだと、TF101 が実行デバイスとして選べるんだよなあ・・・

20130516_android_device_select.jpg
・・・と思いつつ、ASUS Sync をアップデートして、ASUS Android USB Driver も更新したら、とうとう ADT bundle 版の Eclipse でも、TF101 見えなくなっちゃったけど(^^;

adb.exe が問題なのかと調べてみたところ、

C:\Program Files (x86)\ASUS\ASUS Sync\adb.exe

が実行されていた。
他にも、adb.exe はこんなにあった。

C:\usr\local\adt-bundle\sdk\platform-tools\adb.exe
C:\Program Files\Adobe\Adobe Flash Builder 4.7 (64 Bit)\eclipse\plugins\com.adobe.flash.compiler_4.7.0.349722\AIRSDK\lib\android\bin
C:\Program Files\Adobe\Adobe Flash Builder 4.7 (64 Bit)\sdks\4.6.0\lib\android\bin\adb.exe
C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.6\sdks\4.6.0\lib\android\bin\adb.exe

ああ、なるほど、C:\usr\local\adt-bundle\sdk\platform-tools\adb.exe が実行されるようにしないといけないんだな・・・と思って path を通してみたけど、ASUS Sync が必ず C:\Program Files (x86)\ASUS\ASUS Sync\adb.exe を実行しちゃうな・・・

さて、ASUS Sync をアンインストールしてみるか・・・と今まさに思っているところ。

ホント、Android の開発も面倒くせえなあ(^^;
昨日、Perl で作成した GCM メッセージ送信サーバの話。

どうも、昨日、CPAN で WWW::Google::Cloud::Messaging をインストールしてからだと思うのだが(結局、この Perl モジュールは使ってないけど(^^;)、LWP モジュールを呼ぶと、

# ./gcm_message_send.pl
*******************************************************************
 Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
 is depreciated! Please set SSL_verify_mode to SSL_VERIFY_PEER
 together with SSL_ca_file|SSL_ca_path for verification.
 If you really don't want to verify the certificate and keep the
 connection open to Man-In-The-Middle attacks please set
 SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
*******************************************************************
  at /usr/lib/perl5/site_perl/5.8.8/LWP/Protocol/http.pm line 31
id=0:13685930XXXXXXXX%XXXX249ace0038c9

という感じで、エラーが出るようになった。
一応、メッセージ自体は送られているからエラーじゃないな。ワーニングだな。

どうも、WWW::Google::Cloud::Messaging のインストール時に、関連モジュールとして IO::Socket::SSL 関係もバージョンアップされちゃった臭いな(^^;

IO::Socket::SSL のバージョンが上がってセキュリティ関係に厳しくなって、「Man-In-The-Middle アタック の可能性があるので、サーバーとクライアントの間でホスト同士の証明書を交換するか、情報漏洩の可能性を承知で使うために、SSL_VERIFY_NONE を明示的に設定しましょう」ということのようであります。

取り敢えず、証明書交換はせず、SSL_VERIFY_NONE の設定で行きたいので、LWP::UserAgent のコンストラクタで、

my $ua = LWP::UserAgent->new(
ssl_opts => {
verify_hostname => 0,
SSL_verify_mode => SSL_VERIFY_NONE,
}
);

という具合に SSL_verify_mode オプションに定数 SSL_VERIFY_NONE をセットしてみたり、直接 0 をセットしてみたりしても状況変わらず。
む~ん(^^;

結局、LWP::UserAgent は SSL 接続のバックエンドとして Net::SSL も使えるってことだったので、環境変数 'PERL_NET_HTTPS_SSL_SOCKET_CLASS' に Net::SSL を指定し、IO::Socket::SSL を使わないようにしたらワーニングは出なくなった。

こんな感じ。

#!/usr/bin/perl
#
# gcm_message_send.pl
#

use LWP;

$ENV{'PERL_NET_HTTPS_SSL_SOCKET_CLASS'} = "Net::SSL";
$ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;

my $ua = LWP::UserAgent->new;
my $res = $ua->post(
"https://android.googleapis.com/gcm/send",
{
'registration_id' => "APA91bHi1fbAcCk1qwCMu6jO4IlJuAtXXXXXXXX_hhyK7atS6i6G_GuhtprPGroMnZkNQvKTWuAPxXXXXXXXXTLv-mKpIi_Ek9CpDPWvJQ79IZjmyXXXXXXXXttIgKOcf-GTcHRC8VmND3UpXXXXXXXXvfC4bw5hJw",
'collapse_key' => 'update',
'data.message' => "これはテストメッセージです",
},
"User-Agent"    => "NAF Perl Program/0.1",
"Authorization" => "key=AIzaSyDsXXXXXXXX9Lyazw0NYRVrXXXXXXXXHk",
"Content-Type"  => "application/x-www-form-urlencoded;charset=UTF-8"
);

print $res->content . "\n";

ま、これでいいか。(結局、環境変数のセット処理を 2行追加しただけだし(笑))

それに、現実的に、中間者攻撃で我が社の GCM メッセージが改ざんされる可能性は果てしなくゼロに近いからな(笑)
Android GCM のサーバ用の API キーの入手を行なう時、「Create new Server key」を選択する。

そうすると、その API キーを使用するサーバを IP アドレスで指定出来るので、セキュリティ上良いんですわ。

Accept requests from these server IP addresses の入力欄に、一行に 1IPずつ記入する。
うちの会社はインターネット上にテスト用のサーバを 3台持ってるんで、それらの IP アドレスを記入する。

こんな感じ。

181.XXX.XXX.105/32
213.XXX.XXX.127/32
124.XXX.XXX.122/32

1台ずつの設定なので 32ビットのネットマスクをかけているが、複数のサーバを指定することも出来る。
その時は、

221.XXX.XXX.0/24

みたいに設定するわけですわ。

で、この IP アドレス以外のサーバから、GCM サーバにメッセージを送信してみた。

本来なら、id=0:1368593107767685%921c249ace0038c9 みたいなメッセージIDが返ってくるんだけど、

$ ./gcm_message_send.pl
<HTML>
<HEAD>
<TITLE>Unauthorized</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Unauthorized</H1>
<H2>Error 401</H2>
</BODY>
</HTML>

という具合に、401 Unauthorized エラーの HTML ソースが返ってくる。

GCM サーバ(https://android.googleapis.com/gcm/send)を閲覧する権限が無いってわけだな。

バッチリじゃん!
GCM のクライアントのテスト。

ADT 導入済みの Eclipse で、Android SDK Manager を起動して Extras→Google Cloud Messaging for Android Library をインストールする。

20130515_Android2.jpg
そしたら、SDK Path(うちの場合は C:\usr\local\adt-bundle\sdk)\extras\google\gcm\samples の下に gcm-demo-client というクライアントのサンプルプログラムができているので、これを Eclipse でビルド&実行する。

手順としては、「Android アプリケーション・プロジェクト」を gcm-demo-client とか適当な名前で作成し、libs、res、src ディレクトリの中は一旦全部削除して、SDK Path\extras\google\gcm\samples\gcm-demo-client の中身で上書きするっていう具合にしてるんだけど、もっとサンプルソースをプロジェクトに組み込む良いやり方があるのかね?

これで、プロジェクトの実行を行なうと、USB 接続された実機を使うか、それともエミュレータを使うか聞かれるので、実機 ASUS TF101 を選択。TF101 上でサンプルプログラムが実行される。

で、TF101 に向けてメッセージをプッシュすると、端末下部にそのメッセージが表示されるんだけど、それは数秒ですぐ消えちゃうので、サンプルプログラム上にメッセージを表示するように、ちょっとプログラムを修正する。

Android GCM 受信したメッセージを表示」というサイトなどを参考に。

具体的には、GCMIntentService.java を修正。

import android.os.Bundle;
を追加して、onMessage を、

    protected void onMessage(Context context, Intent intent) {
        Log.i(TAG, "Received message");

        // ここから追加&修正
        Bundle extras = intent.getExtras();
        String result = extras.getString("message");
        //String message = getString(R.string.gcm_message);
        String message = getString(R.string.gcm_message) + " = " + result;
        // ここまで
        displayMessage(context, message);
        // notifies user
        generateNotification(context, message);
    }

こんな風に修正。

これで、

20130515_Android1.jpg
こんな感じで、プッシュしたメッセージがアプリ画面にも表示される。

ちなみに、最初のメッセージが化けているのは EUC-JP で送ったから(^^;;;
当然メッセージは UTF-8 で送らないと駄目駄目。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちAndroidカテゴリに属しているものが含まれています。

次のカテゴリはMacです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。


月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら