AndroidとiOSで端末の地域設定を取得する
■Android
Locale.getDefault().toString()
■iOS
[[NSLocale currentLocale] localeIdentifier];
TrackBack URL :
Comments (0)日々勉強
Locale.getDefault().toString()
[[NSLocale currentLocale] localeIdentifier];
TrackBack URL :
Comments (0)素晴らしいライブラリのお陰で5分で接続できる。
package info.justoneplanet.android.eew;
import java.net.URI;
import java.net.URISyntaxException;
import org.java_websocket.WebSocketClient;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class EarthquakeEarlyWarningActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
URI uri = new URI("ws", null, "123.123.123.123", 443, "/", null, null);
WebSocketClient c = new WebSocketClient(uri, new Draft_17()) {
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.e("onOpen", handshakedata.toString());
}
@Override
public void onMessage(String message) {
Log.e("onMessage", message);
}
@Override
public void onError(Exception ex) {
Log.e("onError", ex.toString());
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.e("onClose", reason.toString());
}
};
c.connect();
}
catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
あとは以下のパーミッションを付加する。
<uses-permission android:name="android.permission.INTERNET" />
メインスレッド以外で使うには以下のようにする。
package info.justoneplanet.android.eew;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Random;
import org.java_websocket.WebSocketClient;
import org.java_websocket.drafts.Draft_17;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Notification;
import android.app.NotificationManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
public class Widget extends AppWidgetProvider {
private WebSocketClient client;
private HandlerThread sWorkerThread;
private Handler sWorkerQueue;
private Server[] mServers;
private class Server {
String host;
int port;
public Server(String host, int port) {
this.host = host;
this.port = port;
}
}
public Widget() {
super();
sWorkerThread = new HandlerThread("Widget-worker");
sWorkerThread.start();
sWorkerQueue = new Handler(sWorkerThread.getLooper());
mServers = new Server[]{
new Server("123.123.123.123", 80)
};
}
@Override
public void onEnabled(final Context context) {
super.onEnabled(context);
}
@Override
public void onUpdate(final Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.e("onUpdate", "onUpdate");
sWorkerQueue.removeMessages(0);
try {
Random rand = new Random();
Server server = mServers[rand.nextInt(mServers.length) % mServers.length];
URI uri = new URI("ws", null, server.host, server.port, "/", null, null);
sWorkerQueue.post(new WebSocketClient(uri, new Draft_17()) {
private String chunk;
private RemoteViews remoteViews;
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.e("onOpen", handshakedata.toString());
Toast.makeText(context, handshakedata.toString(), Toast.LENGTH_LONG);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
}
@Override
public void onMessage(String message) {
Log.e("onMessage", message);
remoteViews.setTextViewText(R.id.info, context.getString(R.string.connected));
ComponentName componentName = new ComponentName(context, Widget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(componentName, remoteViews);
}
@Override
public void onError(Exception ex) {
Log.e("onError", ex.toString());
remoteViews.setTextViewText(R.id.info, ex.toString());
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.e("onClose", reason);
remoteViews.setTextViewText(R.id.info, reason);
client.connect();
}
});
}
catch (URISyntaxException e1) {
e1.printStackTrace();
}
}
}
再接続処理とかしないといけない。
TrackBack URL :
Comments (0)ログアウト後のログインが上手くできなくてハマったのでメモしておく。
class AppController extends Controller {
public $components = array(
'Auth' => array(
'loginRedirect' => array('controller' => 'hoge', 'action' => 'index'),
'loginAction' => array('controller' => 'hoge', 'action' => 'login'),
'authenticate' => array(
'Form' => array(
'userModel' => 'Hoge',
'fields' => array(
'username' => 'email',
),
'scope' => array(
'Hoge.is_public' => 1,
),
),
),
),
'Session'
);
public function beforeFilter() {
parent::beforeFilter();
}
}
class HogeController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow(array('login', 'logout', 'fuga'));// loginとlogoutも記述しておく
}
public function login() {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
}
else {
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
public function logout() {
$this->redirect($this->Auth->logout());
}
}
TrackBack URL :
Comments (0)WebViewっぽくならないようにバウンスをさせないようにし、HTTPリクエストにカスタムヘッダーを付加するようにした。たいしてカスタマイズしてない。
#import <UIKit/UIKit.h> @interface CustomWebView : UIWebView @end
#import "CustomWebView.h"
@implementation CustomWebView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {// Initialization code
// バウンスさせない
for (id subview in self.subviews) {
if ([[subview class] isSubclassOfClass: [UIScrollView class]]) {
((UIScrollView *)subview).bounces = NO;
}
}
}
return self;
}
- (void)loadRequest:(NSURLRequest *)request
{
// カスタムヘッダーの付加
NSMutableURLRequest *mutableRequest = (NSMutableURLRequest *)[request mutableCopy];
[mutableRequest setValue:@"iOS.UIWebView" forHTTPHeaderField:@"App-Client"];
[super loadRequest:mutableRequest];
}
@end
以下のようにオフライン時の画面を表示するメソッドを作ってあげてもいいと思う。
- (void)displayOfflineView
{
if (self) {
NSString *path = [[NSBundle mainBundle] pathForResource:@"offline" ofType:@"html"];
[self loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
}
}
webviewを表示した時に圏外の場合、圏内になった時にreloadをしても正しく表示ができないので以下のようなメソッドも加えておく。
- (void)dealloc
{
if (initialRequest) {
[initialRequest release];
}
[super dealloc];
}
- (void)reload
{
if (self) {
if ([self canGoBack]) {
[super reload];
}
else if (initialRequest) {
[self loadRequest:initialRequest];
}
}
}
- (void)loadRequest:(NSURLRequest *)request
{
[super loadRequest:request];
if (!initialRequest) {
initialRequest = [request retain];
}
}
TrackBack URL :
Comments (0)分かりやすいものから分かりにくいものまであるのでとりあえずメモしておく。
// http://user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
NSURL *url = [request URL];
[url scheme];// http
[url host];// hogehoge.com
[url absoluteString];// http://user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
[url absoluteURL];// http://user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
[url baseURL];
[url fragment];// hoge
[url host];// hogehoge.com
[url lastPathComponent];// test.html
[url parameterString];
[url password];// pass
[url path];// /dir/use/test.html
[url pathComponents];// ("/",dir,d,"test.html")
[url pathExtension];// html
[url port];// 1234
[url query];// q=sample
[url relativePath];// /dir/use/test.html
[url relativeString];// http://user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
[url resourceSpecifier];// //user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
[url standardizedURL];// http://user:pass@hogehoge.com:1234/dir/d/test.html?q=sample#hoge
[url user];// user
TrackBack URL :
Comments (0)
hash_hmac('md5', $str, 'hogehogehoge');
public class HmacMD5 {
private static final String ALGORISM = "HmacMD5";
private static final String S = "hogehogehoge";
public static String get(String str) {
SecretKeySpec secretKeySpec = new SecretKeySpec(S.getBytes(), ALGORISM);
try {
Mac mac = Mac.getInstance(ALGORISM);
mac.init(secretKeySpec);
byte[] result = mac.doFinal(str.getBytes());
return byteToString(result);
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (InvalidKeyException e) {
e.printStackTrace();
}
return "";
}
private static String byteToString(byte [] b) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < b.length; i++) {
int d = b[i];
d += (d < 0)? 256 : 0;
if (d < 16) {
buffer.append("0");
}
buffer.append(Integer.toString(d, 16));
}
return buffer.toString();
}
}
日本語入力に対応するためにstackoverflowから持ってきたコードに少々手を入れた。
+ (NSString *)HMACMD5WithKey:(NSString *)data
{
const char *cKey = [@"hogehogehoge" cStringUsingEncoding:NSUTF8StringEncoding];
const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
const unsigned int blockSize = 64;
char ipad[blockSize];
char opad[blockSize];
char keypad[blockSize];
unsigned int keyLen = strlen(cKey);
CC_MD5_CTX ctxt;
if (keyLen > blockSize) {
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, cKey, keyLen);
CC_MD5_Final((unsigned char *)keypad, &ctxt);
keyLen = CC_MD5_DIGEST_LENGTH;
}
else {
memcpy(keypad, cKey, keyLen);
}
memset(ipad, 0x36, blockSize);
memset(opad, 0x5c, blockSize);
int i;
for (i = 0; i < keyLen; i++) {
ipad[i] ^= keypad[i];
opad[i] ^= keypad[i];
}
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, ipad, blockSize);
CC_MD5_Update(&ctxt, cData, strlen(cData));
unsigned char md5[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(md5, &ctxt);
CC_MD5_Init(&ctxt);
CC_MD5_Update(&ctxt, opad, blockSize);
CC_MD5_Update(&ctxt, md5, CC_MD5_DIGEST_LENGTH);
CC_MD5_Final(md5, &ctxt);
const unsigned int hex_len = CC_MD5_DIGEST_LENGTH*2+2;
char hex[hex_len];
for(i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
snprintf(&hex[i*2], hex_len-i*2, "%02x", md5[i]);
}
NSData *HMAC = [[NSData alloc] initWithBytes:hex length:strlen(hex)];
NSString *hash = [[[NSString alloc] initWithData:HMAC encoding:NSUTF8StringEncoding] autorelease];
[HMAC release];
return hash;
}
TrackBack URL :
Comments (0)zxing-x.x/iphone/ZXingWidget/を自身のプロジェクトのプロジェクトナビゲーターにドロップする。
Target DependenciesでZXingWidgetを追加した後、Link Binary With Librariesで以下を追加する。
Header Search Pathsに以下の項目を追加する。
前者はrecursiveにチェックを入れて、後者はチェックを入れない。
#import <UIKit/UIKit.h>
#import "ZXingWidgetController.h"
@interface ScanViewController : UIViewController<ZXingDelegate>{
UITextView *resultView;
NSString *resultStr;
}
@property (nonatomic, retain) UITextView *resultView;
@property (nonatomic, copy) NSString *resultStr;
- (void)scanPressed:(id)sender;
@end
ファイルの拡張子を.mmとしないとコンパイルできない。
#import "ScanViewController.h"
#import "QRCodeReader.h"
@implementation ScanViewController
@synthesize resultView;
@synthesize resultStr;
- (void)scanPressed:(id)sender
{
ZXingWidgetController *widController = [[ZXingWidgetController alloc] initWithDelegate:self showCancel:YES OneDMode:NO];
QRCodeReader* qrcodeReader = [[QRCodeReader alloc] init];
NSSet *readers = [[NSSet alloc ] initWithObjects:qrcodeReader,nil];
[qrcodeReader release];
widController.readers = readers;
[readers release];
[self presentModalViewController:widController animated:YES];
[widController release];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)dealloc {
[resultView release];
}
#pragma mark - View lifecycle
- (void)loadView
{
[super loadView];
UIButton *btnStamp = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnStamp setFrame:CGRectMake(40, 220, 240, 50)];
[btnStamp setTitle:@"QRコードを読み取る" forState:UIControlStateNormal];
[btnStamp setTag:1];
[btnStamp addTarget:self action:@selector(scanPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnStamp];
resultView = [[UITextView alloc] initWithFrame:CGRectMake(40 , 280, 240, 50)];
[self.view addSubview:resultView];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma mark ZXingDelegateMethods
- (void)zxingController:(ZXingWidgetController*)controller didScanResult:(NSString *)result {
self.resultStr = result;
if (self.isViewLoaded) {
[resultView setText:resultStr];
[resultView setNeedsDisplay];
}
[self dismissModalViewControllerAnimated:NO];
}
- (void)zxingControllerDidCancel:(ZXingWidgetController*)controller {
[self dismissModalViewControllerAnimated:YES];
}
@end
こんな感じで。
TrackBack URL :
Comments (0)setAccessoryViewしただけだとタップした時にaccessoryButtonTappedForRowWithIndexPathが発火しなくなるので以下のようにする。
// create cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// call cell
UITableViewCellFixed *cell = (UITableViewCellFixed *)[tableView dequeueReusableCellWithIdentifier:@"table_cell"];
if (cell == nil) {// create cell
cell = [[[UITableViewCellFixed alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"table_cell"] autorelease];
}
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(0, 0, 26, 26)];
[button setBackgroundImage:[UIImage imageNamed:@"arrow.png"] forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor clearColor]];
[button addTarget:self action:@selector(accessoryButtonTapped:withEvent:) forControlEvents:UIControlEventTouchUpInside];
[cell setAccessoryView:button];
return cell;
}
- (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event
{
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:[[[event touchesForView: button] anyObject] locationInView:self.tableView]];
if (indexPath == nil) {
return;
}
[self.tableView.delegate tableView: self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
TrackBack URL :
Comments (0)yum install openssl-devel gcc-c++ make#前準備 wget http://nodejs.org/dist/v0.6.11/node-v0.6.11.tar.gz tar xvzf node-v0.6.11.tar.gz cd node-v0.6.11 ./configure make make install curl http://npmjs.org/install.sh | sh npm install -g express express sample cd sample npm install
たまたま80番開いていたので以下のようにして80番で繋がるようにする。
/**
* Module dependencies.
*/
var express = require('express')
, routes = require('./routes');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Routes
app.get('/', routes.index);
app.listen(80);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
node app.js
http://ec2-123-123-123-123.ap-northeast-1.compute.amazonaws.com/などで自分のインスタンスにアクセスすれば見れる。
以下のように編集する。
{
"name": "application-name"
, "version": "0.0.1"
, "private": true
, "dependencies": {
"express": "2.5.8"
, "jade": ">= 0.0.1"
, "socket.io": "*"
}
}
./sampleで以下のコマンドを実行する。
npm install
サーバー側のコードをapp.jsの最後尾に付加する。
var io = socketio.listen(app)
,count = 0;
io.sockets.on('connection', function(socket){
count++;
io.sockets.emit('count change', count);
socket.on('disconnect', function() {
count--;
socket.broadcast.emit('count change', count);
}
);
});
クライアント側の処理を書き加える。
!!!
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
script(type='text/javascript', src='http://code.jquery.com/jquery.min.js')
script(type='text/javascript', src='/socket.io/socket.io.js')
script(type='text/javascript')
var socket = io.connect();
socket.on('count change', function(count) {
$('#count').text(count);
});
body!= body
表示用に要素を追加する。
#page
#headerArea
h1= title
p Welcome to #{title}
p 現在このページを見ている人は
span#count
人います。
既存のhtmlコードを使用するときにhamlにするのは手間なのでejsを使う。
以下のように編集する。
{
"name": "application-name"
, "version": "0.0.1"
, "private": true
, "dependencies": {
"express": "2.5.8"
, "jade": ">= 0.0.1"
, "socket.io": "*"
, "ejs": "*"
}
}
以下のようにして、テンプレートエンジンをjadeからejsに変更する。
/**
* Module dependencies.
*/
var express = require('express')
, socketio = require('socket.io')
, ejs = require('ejs')
, routes = require('./routes');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('view options', {layout : false});
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
せっかくなんでルーティングも変更してみる。
app.get('/', routes.index);
app.get('/hoge', function(req, res) {
res.render('hoge.ejs', { title: 'My Site' });
});
あとは以下のようにテンプレートファイルを用意する。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<title><%= title %></title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect();
socket.on('count change', function(count) {
$('#count').text(count);
});
</script>
</head>
<body>
<h1><%= title %></h1>
<p>現在このページを見ている人は<span id="count"></span>人います。</p>
</body>
</html>
以下のようなURLでアクセスができるようになる。
http://ec2-123-123-123-123.ap-northeast-1.compute.amazonaws.com/hoge
TrackBack URL :
Comments (0)
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
SearchFragment fragment = (SearchFragment) Fragment.instantiate(getActivity(), SearchFragment.class.getName(), null);
Bundle bundle = new Bundle();
bundle.putString("word", word);
fragment.setArguments(bundle);
ft.replace(R.id.content, fragment).addToBackStack("result");
ft.commit();
getActivity().getSupportFragmentManager().executePendingTransactions();
mWord = getArguments().getString("word");
TrackBack URL :
Comments (0)