ときどきプログラミング

プログラミングとかで遊んで面白かったことをシェアするブログ

デベロッパーモードで入れた自作のChrome extensionが勝手に無効にされる問題を回避(crxを無理やり入れる方法)

問題点
Chromeのv35からChrome拡張機能がChromeWebStoreからダウンロードしたもの
でないと有効にならない様子。
デベロッパーモードで入れていると無効にされるため、自作のChrome拡張が
使えないという不都合な状態。

■まず、chromeデベロッパーモードを有効にして、
自作crxをドラッグ&ドロップで入れる。入れると、IDが表示されるので控えておく。

■次にchromeの用意したポリシーテンプレートを落としてくる。
http://www.chromium.org/administrators/policy-templates にアクセスして、
[Zip file of ADM/ADMX templates and documentation]をダウンロード&解凍しておく。

■スタートメニュー→ファイル名を指定して実行から、[gpedit.msc]と入力&起動。
コンピュータの構成→管理用テンプレートを右クリックして
「テンプレートの追加と削除」を開き、追加(A)から、
先程ダウンロード&解凍したフォルダの中から、
policy_templates\windows\adm\jaとたどり、chrome.admというのを選択して追加する。

■コンピュータの構成→管理用テンプレート→従来の管理用テンプレート(ADM)→
GoogleGoogle Chrome拡張機能拡張機能インストールのホワイトリスト
設定するをダブルクリックで開く。
有効(E)にチェックを入れ、ブラックリストから除外する拡張機能IDの[表示...]をクリック。
値に、先程控えたIDを入力してOKをクリック。

■あとは、chromeで確認。
デベロッパーモードを無効にしても、
追加した自作crxが有効状態になっているようなのでOKそう。

■さらに確認。
chromeのアドレスに [chrome://policy] と入れて開いたページに、
ポリシー名にExtensinInstallWhitelist、ポリシーの値にID、ステータスにOKと入っていればOK。

Google検索で上部メニューの並びが勝手に変化するのが不便なのでjQuery+Chromeエクステンションで簡単に解決してみた

※更新ver1.0.1 Googleの仕様変更で上手く動作していなかったので修正 2015/03/01 12:57

最近、Google検索にある上部の検索メニュー「ウェブ|画像|動画|地図|ニュース…」の順番が、検索内容によって勝手に変わる仕様になった。 自分の頭のなかでは、メニューの二番目は画像なので、何も考えずにクリックしたら、勝手に地図が表示されたりする。

参考:

Google、検索クエリに合わせて検索メニューが変化する仕様に

Googleのクソアップデートきた!検索メニューの『ウェブ/画像/地図/動画』などが自動で入れ替わるようになった

新仕様?Google検索のメニュー並びがクエリで勝手に変化

嫌だったので、jQueryChromeのエクステンションを作ってみました。

ダウンロード&インストール

Chromeウェブストアで配布しています。

Googleの検索メニューの順番を固定にする。(Chromeウェブストア)

ソースコード

ダウンロード(zipファイル)

下記の3つのファイルで構成されています。

  • manifest.json
  • main.js
  • jquery.min.js (version 1.11.0)

manifest.json

{
  "name": "Googleの検索メニューの順番を固定にする。",
  "version": "1.0.1",
  "manifest_version": 2,
  "description": "Googleの検索メニューの順番を固定にする。",
  "content_scripts": [
    {
      "matches": [
        "https://*.google.co.jp/*",
        "https://*.google.co.jp/*",
        "https://*.google.com/*",
        "http://*.google.co.jp/*",
        "http://*.google.com/*"
      ],
      "js": ["jquery.min.js","main.js"],
      "run_at": "document_start"
    }
  ]
}

main.js

var lists = {
    "ウェブ":"",
    "画像":"isch",
    "動画":"vid",
    "地図":"map",
    "ニュース":"nws",
    "ショッピング":"shop",
    "書籍":"bks",
    "アプリ":"app"
};

$(function(){
    setInterval(function(){
        fixMenu();
    }, 700);
});

function fixMenu() {
    var q = $("input#lst-ib").val();
    var tbm = $("input[name='tbm']").val();
    var dom = "";
    $.each(lists, function(key, val) {
        if(val==tbm) {
            dom += "<div class=\"hdtb_mitem  hdtb_msel\">"+key+"</div>";
        }
        else if(val=="map") {
            dom += "<div class=\"hdtb_mitem\"><a class=\"q qs\" href=\"//maps.google.com/maps?q="+q+"\">"+key+"</a></div>";
        }
        else {
            dom += "<div class=\"hdtb_mitem\"><a class=\"q qs\" href=\"/search?q="+q+"&tbm="+val+"\">"+key+"</a></div>";
        }
    });
    $("div.hdtb_mitem").remove();
    $("a#hdtb_more").remove();
    $("div#hdtb_msb").prepend(dom);
}

Amazonで本を検索すると同時に、喜久屋書店にも在庫があるかを確認できるChromeエクステンションをjQueryで作った

※更新 ver1.0.4 喜久屋書店の仕様変更で上手く表示されてなかったので修正 2015/03/01 14:49

Amazonで本を検索したときに、喜久屋書店に在庫があるかどうかを そのページ内にシームレスで表示するChromeエクステンションです。

f:id:kurashiki8bit:20140424102337p:plain

その本、図書館にあります。にインスパイアされています。

主にjQueryで制作しました。

jQueryで作ると、とても簡単なコードだけで出来ました。 面白かったのでソースも公開します。 改変自由なので、あなたも「その本、〇〇にあります。」を作ってみてください。

ダウンロード&インストール

Chromeウェブストアで配布しています。

その本、喜久屋書店にあります。(Chromeウェブストア)

ソースコード

ダウンロード(zipファイル)

下記の6つのファイルで構成されています。

  • manifest.json
  • main.js
  • options.html
  • options.js
  • background.js
  • jquery.min.js (version 1.11.0)

manifest.json

Chromeエクステンションは、マニフェストファイルと呼ばれるJSONフォーマットのファイルを manifest.json という名前で持つ必要があるらしい。ここにエクステンションの情報とかを定義するみたい。 permissionsの http://61.120.69.13/* は、喜久屋書店のサーバIPへの問い合わせアクセスを許すという意味。 content_scriptsのmatchesが動作対象のURL。ここではAmazonの検索後のページでのみ動くように指定。

{
  "name": "その本、喜久屋書店にあります。",
  "version": "1.0.3",
  "manifest_version": 2,
  "description": "その本、喜久屋書店にあります。",
  "permissions": [
    "http://61.120.69.13/*"
  ],
  "content_scripts": [
    {
      "matches": [
        "http://www.amazon.co.jp/*dp/*",
        "http://www.amazon.co.jp/gp/product/*"
      ],
      "js": ["jquery.min.js","main.js"],
      "run_at": "document_start"
    }
  ],
  "background": {
    "scripts": ["background.js"]
  },
  "options_page": "options.html"
}

main.js

一番のメイン部分。Amazonページ内にISBNがあった場合、その値を取得して、$.ajax喜久屋書店の検索CGIにGETで問い合わせに行く。返ってきた値(ページ全体)に店舗名が入っていれば在庫ありと判断して、その結果をAmazonのページ内に追記(afterやbefore)する。

始めの、chrome.runtime.sendMessageは、オプションページで設定した店舗名(loadStorageの値)をbackground.js経由でshop変数に入れています。ここだけ分かりにくいですが、こうしないと取得できなかったのでこうしてます。

$(function(){
    var shop = "";
    chrome.runtime.sendMessage({}, function(response) { // オプションページの設定(localStorageの値)をshop変数に入れる
        shop = response.shop;
    });
    $("li").each(function(){
        if($(this).html().match(/ISBN-13/)){
            var matches = $(this).html().match(/^<b>(ISBN-13):<\/b> (.+)$/); // AmazonからISBNを取得
            var isbn13 = matches[2].replace("-","");
            var url = "http://61.120.69.13/k_detail.jsp"; // 喜久屋書店側の検索CGI
            $.ajax({
                type: "GET",
                dataType: "html",
                url: url,
                data: { "ISBN":isbn13, "VIEW":"word", "ARGS":isbn13 },
                beforeSend: function(xhr){ xhr.overrideMimeType("text/html;charset=Shift_JIS"); } // アクセス先ページはShift_JIS
            })
            .done(function(data){
                var title = "<font color=chocolate>この本が喜久屋書店にあるか検索</font> → ";

                if(shop=="全店") { 
                    var pattern = new RegExp("喜久屋書店 ");
                } else {
                    var pattern = new RegExp("喜久屋書店 "+shop);
                } 

                if(data.match(pattern)) { // 検索結果を調べる
                    var ans = "喜久屋書店("+shop+") 在庫あり";
                    var color = "#009900"; // 緑
                }
                else{
                    var ans = "喜久屋書店("+shop+") 在庫なし";
                    var color = "#990000"; // 赤
                }

                // Amazonに追記するhtmlタグを作る
                var html = title+"<a style=\"color:"+color+"\" target=\"new\" href=\""+url+"?ISBN="+isbn13+"&VIEW=word&ARGS="+isbn13+"\"><b>"+ans+"</b></a>";
                if($("div#dynamicDeliveryMessage_feature_div").length) {
                    $("div#dynamicDeliveryMessage_feature_div").before(html);
                }
            });
        }
    });
});

options.html

喜久屋書店には複数の店舗があるので、検索対象の店舗をユーザがオプションで設定できるようにと作りました。ただのhtmlですね、とても簡単。

<html>
<head>
<meta charset="utf-8"/>
<title>その本、喜久屋書店にあります。</title>
<script src="options.js"></script>
</head>
<body>
その本、喜久屋書店にあります。<br>
<br>
店舗を指定して下さい。<br>
<br>
喜久屋書店
<select name="shop" id="shop">
<option value="全店">全店</option>
<option value="小樽店">小樽店</option>
<option value="漫画館仙台店">漫画館仙台店</option>
<option value="宇都宮店">宇都宮店</option>
<option value="太田店">太田店</option>
<option value="千葉ニュータウン店">千葉ニュータウン店</option>
<option value="高岡店">高岡店</option>
<option value="大垣店">大垣店</option>
<option value="草津店">草津店</option>
<option value="漫画館京都店">漫画館京都店</option>
<option value="阿倍野店">阿倍野店</option>
<option value="東急ハンズ心斎橋店">東急ハンズ心斎橋店</option>
<option value="寝屋川店">寝屋川店</option>
<option value="奈良駅店">奈良駅店</option>
<option value="橿原店">橿原店</option>
<option value="大和郡山店">大和郡山店</option>
<option value="北神戸店">北神戸店</option>
<option value="神戸北町店">神戸北町店</option>
<option value="東急プラザ新長田店">東急プラザ新長田店</option>
<option value="神戸学園都市店">神戸学園都市店</option>
<option value="西神中央店">西神中央店</option>
<option value="明石駅ビル店">明石駅ビル店</option>
<option value="豊岡店">豊岡店</option>
<option value="倉敷店">倉敷店</option>
<option value="小倉店">小倉店</option>
<option value="熊本店">熊本店</option>
</select>

<button id="save">保存</button>

</body>
</html>

options.js

オプションページで保存ボタンが押された場合、localStorageに店舗の値を保存しています。数行のJavaScriptだけです。

function $(id){
    return document.getElementById(id);
}
function init(){
    if(!localStorage.shop) {
        localStorage.shop = "全店"; // デフォルト値
    }
    $("shop").value = localStorage.shop;
}
function save(){
    localStorage.shop = $("shop").value;
    alert("店舗を"+localStorage.shop+"に変更しました。");
}
window.onload=function(){
    init();
    $('save').onclick=save;
}

background.js

main.jsで直にlocalStorage.shopと書いても(amazon.co.jplocalhostドメインが違うから?)データが取得できなかったので、background.js経由で間接的にlocalStorageの値を取得するようにしました。

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
    var shop = localStorage.shop;
    if(!shop) { shop = "全店"; } // デフォルト値
    sendResponse({shop:shop});
});

あとがき

そもそも、自分だけで使うのであれば、店舗をそのままmain.jsに書けばよいので、オプションページ関連(option.html,option.js,background.js)はいらないし、main.jsはもっとシンプルになります。利便性のため追加しているだけなので、この辺を抜きにして考えてもらうとjQueryChromeエクステンションが非常に簡単に作れていることが分かると思います。

参考

jQuery を使って 30 分で Chrome 拡張を作ってみた

jQueryデザインブック 仕事で絶対に使うプロのテクニック

jQueryデザインブック 仕事で絶対に使うプロのテクニック

ProcessingでAdMobの広告を入れる方法

広告アプリをつくるために、ProcessingでAdMobを表示させましょう。

参考サイト

http://forum.processing.org/one/topic/how-to-including-ads-to-android-project.html

事前準備

  • admobアカウントを作って、パブリッシャーIDを手に入れる。
  • Google Mobile Ads SDKを落としてくる

https://developers.google.com/mobile-ads-sdk/download?hl=ja#downloadandroid

にある、GoogleMobileAdsSdkAndroid.zipをクリック。

しかし、、GoogleAdMobAdsSdk-6.4.1.jarは色々不具合が出る。

(Android-16以上を要求してくるがProcessingはAndroid-10でコンパイルしようとする)

ネットのどっかから、GoogleAdMobAdsSdk-4.1.1.jarを手に入れて使うことにした。

  • 解凍して出来たjarファイルをProcessingのライブラリフォルダに追加する。

「GoogleAdMobAdsSdk-4.1.1.jar」を、「AdMob.jar」 って名前に変える。

  • 場所移動
# cd /Users/***/Documents/Processing/libraries

ここに、AdMobってディレクトリ作成。

さらにAdMobディレクトリの中に。「library」ってディレクトリ作成。

libraryディレクトリの中に、「AdMob.jar」を入れる。

こんな感じ

# ls /Users/***/Documents/Processing/libraries/AdMob/library/AdMob.jar
AdMob.jar

Processingに認識させるため、一度Processingを再起動。

すると、SketchメニューのImport Libraryに AdMobってメニューが増えるのでそれを選択。

pdeファイルの先頭に下記が自動生成される。一旦全部消す。

import com.google.ads.*;
//import com.google.ads.util.*; // こっちはいらないと思われ。

スケッチフォルダにあるAndroidManifest.xmlを編集(赤色のところ)

# vi AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="">
<uses-sdk android:minSdkVersion="10" />
<application android:debuggable="true" android:icon="@drawable/icon" android:label="">
  <activity android:name="">
    <intent-filter>
      <action android:name="android.intent.action.MAIN"/>
      <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
  </activity>
  <activity
   android:name="com.google.ads.AdActivity"
   android:configChanges="keyboard|keyboardHidden|orientation|screenLayout" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

※っていうか、uses-permissionは、あとからProcessingのメニューで、

Android→SketchPermissionsで、ACCESS_NETWORK_STATEとINTERNETに

チェックを入れましたので、ここで記述しなくてもいいのかもしれません。


Processingのタブのところにある、NewTabからAdmob.pdeって名前でスケッチを追加する。

↓ Admob.pdeの中身を下記にする。

import com.google.ads.*;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.RelativeLayout;

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  // 使うのはpub-**********ではなく、ca-app-pub-*************/**********のほうだった。
  AdView adView = new AdView(this, AdSize.BANNER, "ca-app-pub-**********************/**************");
  AdRequest request = new AdRequest();

  // テスト機の指定
  request.addTestDevice(AdRequest.TEST_EMULATOR); // EMULATOR
  request.addTestDevice("11830D3FE8B00999B20BEF2E79999999"); // Genymotion
//  request.setTesting(true); // 全部テスト(これは認識していない気がする)

  adView.loadAd(request);

  RelativeLayout layout = new RelativeLayout(this);
  RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
    RelativeLayout.LayoutParams.FILL_PARENT,
    RelativeLayout.LayoutParams.FILL_PARENT);

  layout.setGravity(Gravity.BOTTOM|Gravity.CENTER);
  layout.addView(adView);

  this.addContentView(layout,lp);
}

Processingは、apk生成時にJAVAコードに一旦変換しているので、別pdeを作って、その中でonCreateをオーバライドして書けばいいだけなんです。とても簡単です。

(追記)Ad request successful, but no ad returned due to lack of ad inventory.

上記のようなエラーがLogcatで出て、うまく表示されないときは言語環境を英語に変更してみたら表示された。

日本語の場合だと表示までに、半日とか時間がかかるらしい。

Processingの開発環境をダークテーマに変える方法

Processingの開発環境はおしゃれじゃない!!

デフォルトのデザインだと、開発する気にさえならないと思いませんか。

私は Sublime text みたいな見た目が好きなのです。

http://www.sublimetext.com/

そこで、Processingの開発環境を下記みたいなダークテーマに変えてみた。

f:id:kurashiki8bit:20140312175603p:plain

実際に行ったのは、Processing2.0.3。

2.1系は日本語にバグあるので使わない。

https://github.com/jeffThompson/DarkProcessingTheme_2.0

上記URLの「Download ZIP」から、DarkProcessingTheme_2.0-master.zipをダウンロード&解凍。

# cd /Applications/Processing.app/Contents/Resources/Java/lib

このフォルダにある、「theme.txt」を解凍した中にある同名ファイルで上書き。

「preferences.txt」は上書きしないでOK。

# cd /Applications/Processing.app/Contents/Resources/Java/modes/java

このフォルダにある、「theme」フォルダを

解凍した中にある同名フォルダで中身ごと上書き。

(この中にあるtheme.txtを編集するとJavaモードの見た目に影響するみたい)

Androidモードを追加している場合は、modesディレクトリ(設定により場所は異なる)に移動。(私はDropboxに入れてる)

# cd /Users/***/Dropbox/Processing/modes/AndroidMode

このフォルダにある、「theme」フォルダを

解凍した中にある同名フォルダで中身ごと上書き。

(この中にあるtheme.txtを編集するとAndroidモードの見た目に影響するみたい)

で、Processingを再起動したらダークテーマになった。


微調整

androidのtheme.txtの一部を書き換え(背景を真っ黒にしたかった)

# vi theme.txt
editor.bgcolor = #000000

エディタの文字をRictyフォントに変えたい。

Processingメニューの環境設定から、最下部の、More preference can be edited 〜を開き、

preferences.txtをエディタで開く。

次に、preferences.txtの編集中は、Processingは終了させておかないと設定が反映されないので、

Processingを一旦終了させる。

※ 実際の場所は、/Users/***/Library/Processing/preferences.txt みたい。

※ /Applications/Processing.appの中にあるpreferences.txtはサンプルなので変えても意味なし。

editor.font=processing.mono,plain,10
editor.font.macosx=Monaco,plain,10

editor.font=Ricty,plain,15
editor.font.macosx=Ricty,plain,15

に変えてProcessingを起動。

文字サイズ15は、Processingの環境設定からEditor font sizeで改めて指定。


他に、起動時の画面サイズが毎回小さいので下記のように変更する。

editor.window.height.default=875
editor.window.width.default=910

p.s. こっちのテーマも気になるなあ。

http://hellowoo.com/processing/dark-theme-syntax-highlighting/

…ちょっとメニューが暗いかな。

Xperia Z SO-03E 実機でデバッグ

Genymotionでもマシンパワーを使うので、実機でしよう。

Xperia Z SO-03Eを使う。100均でUSB→microUSB買う。データ転送対応のやつ。

Android 端末をデバッグオプション ON で USB 接続し、利用する端末のベンダーIDを調べる。

# system_profiler SPUSBDataType
      SO-03E:
         Product ID: 0x518d
   これ→ Vendor ID: 0x0fce  (Sony Ericsson Mobile Communications AB)
         Version: 2.28
         Serial Number: CBF5ABV9A3
         Speed: Up to 480 Mb/sec
         Manufacturer: Sony
         Location ID: 0xfd000000 / 4
         Current Available (mA): 500
         Current Required (mA): 500

USBドライバ設定のmanifest.ini作る

# cd /Users/***/Downloads/adt-bundle-mac-x86_64/sdk/add-ons/
# mkdir xperia-z
# vi xperia-z/manifest.ini
name=Sony Xperia z
Vendor=Sony Ericsson Mobile Communications AB
description=Adds USB support for Xperia Z (Vendor id:0x0fce)
api=16
revision=1
usb-vendor=0x0fce

USBドライバ設定の反映

# ../tools/android update adb

adbの再起動

# adb kill-server
# adb start-server

Xperia Z側での設定

[設定]->[セキュリティ]->[提供元不明のアプリ] OFF->ON

[設定]->[開発者向けオプション]->[USBデバッグ] OFF->ON

デバッグアプリを選択もいる?私はしなかった。

MacとXperiaZを接続後、接続確認

# ../platform-tools/adb devices
List of devices attached
CBF5ABV9A3  device
↑ デバイスが認識されてる。

※PC CompanionはWindows専用なので入れないでOK

これでデバイスは認識したけど、~/.android/adb_usb.ini は空っぽのままだった

(adb_usb.iniに、usb-vendorの値が追記されるらしいが、空っぽのままだった)

そういうもんと思われ。

ProcessingからRUNで入れると下記エラー?

「INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES」

→対象デバイスにプリインストールされている同名のapkを削除したら上手くいった。

GENYMOTIONで仮想Androidを用意する

Android Virtual Devicesは重い。

いつもCPUファンが回り出す。

(Intel x86 Atom System Imageを入れても重いと感じる。)

なので、GENYMOTIONで仮想Androidを用意する。

(Processingから簡単に使える)

http://www.genymotion.com/

(※VirtualBoxに依存するので入れてあげる。)

https://www.virtualbox.org/wiki/Downloads

入ったら、Nexus4かSの仮想端末を作って起動しておけば、

Processingが勝手に認識して、RUNすれば動作した。

(追記)うまくいかない人は、sdkのパスが通っていないのでは?

# vi ~/.bash_profile
export PATH=${PATH}:/Users/**/Downloads/adt-bundle-mac-x86_64/sdk/platform-tools:/Users/**/Downloads/adt-bundle-mac-x86_64/sdk/tools

反映

# source ~/.bash_profile