Android APIレベル23 での Fail to connect to camera service の解決方法


参考サイト:
素人のアンドロイドアプリ開発日記
androidでカメラを使ってみる。


targetSdkVersion を変更したらエラーが出たのでgradleのappcompatのバージョン指定を変更した話。
http://qiita.com/NaokiOgawa/items/9e4fb031e2a0fb1dbbf5


完成したソースは一番下にあります。

再現手順

2015年9月2日、APIレベル23にて確認。


Activity は Blank Activity を選択します。


最初からセットされている処理(Hello World)を
エミュレーターで実行します。成功します。APIレベルは23です。


次に実機(ZenPhone1, Android 4.4)で実行します。成功します。
APIレベルは19です。


素人のアンドロイドアプリ開発日記 を参考に以下の処理を組み込みます。
androidでカメラを使ってみる。


AndroidManifest.xmlの変更

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

を追加。


android:screenOrientation="landscape"

を追加。


クラス CameraView の追加

参照元サイトをご確認ください。


クラス MainActivity の変更

setContentView(R.layout.activity_main);

コメントアウトして

CameraView view = new CameraView(this);
setContentView(view);

を追加。


エミュレーターで実行します。
すると
java.lang.RuntimeException: Fail to connect to camera service
のエラーになります。


エラーの原因

APIレベル23では、Camera.open(); が使えないことが原因です。
APIレベル23では
https://github.com/googlesamples/android-Camera2Basic
を参考に、Camera2 APIを使用します。



解決方法

APIレベルを下げます。ここでは実機のAPIレベル19にします。
以下を実施します。


参考サイト
targetSdkVersion を変更したらエラーが出たのでgradleのappcompatのバージョン指定を変更した話。
http://qiita.com/NaokiOgawa/items/9e4fb031e2a0fb1dbbf5


build.gradleの変更

Gradle Script の下にあるBuild.gradeleを以下のよう変更します。

targetSdkVersion 23

targetSdkVersion 19



compile 'com.android.support:appcompat-v7:23.0.0'

compile 'com.android.support:appcompat-v7:19+'



実行すると以下のエラーになります。


Error:(3, 30) エラー: シンボルを見つけられません
シンボル: クラス AppCompatActivity
場所: パッケージ android.support.v7.app


エラーの原因

APIレベル19ではクラス AppCompatActivityが存在しないことが原因です。


MainActivity.javaの変更

import android.support.v7.app.AppCompatActivity;

import android.app.Activity;



public class MainActivity extends AppCompatActivity {

public class MainActivity extends Activity {

に変更します。


エミュレータで実行します。APIレベルが低いことの警告が出ますが、OKを押します。

起動が成功します。



しかし、実機で起動すると以下のエラーになります。
java.lang.RuntimeException: setParameters failed


エラーの原因

setParameters のエラーで、プレビューのサイズを指定する必要があります。


CameraView.javaの変更

parameters.setPreviewSize(width, height);

List<Camera.Size> previewSizes = myCamera.getParameters().getSupportedPreviewSizes();
Camera.Size size = previewSizes.get(0);
parameters.setPreviewSize(size.width, size.height);

に変更します。


実機での起動が成功します。



補足 AndroidManifest.xmlの変更(フルスクリーンにしたい場合)

android:theme="@style/AppTheme" 

android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" 

に変更します。
APIレベル23の場合の、以下の記述と同じです。
android:theme="@style/Theme.AppCompat.NoActionBar" )


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.github.fumio_shimamura.image04" >

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="landscape" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity.java

package com.github.fumio_shimamura.image04;

//import android.support.v7.app.AppCompatActivity;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);

        CameraView view = new CameraView(this);
        setContentView(view);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.0"

    defaultConfig {
        applicationId "com.github.fumio_shimamura.image04"
        minSdkVersion 15
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19+'
}

iPhone 日記アプリの作り方(2)ソースコード

もくじページ
http://d.hatena.ne.jp/seika_m/20150822

ソースコード

GitHub
https://github.com/fumio-shimamura/flipdiary/tree/master/FlipDiary

GitHubにある、以下のファイルの処理をコピーして下さい。


AppDelegate.h
AppDelegate.m
Article.h
Article.m
DataViewController.h
DataViewController.m
ModelController.h
ModelController.m
RootViewController.h
RootViewController.m
TableViewController.h
TableViewController.m


画面遷移処理(ソースコードが必要な物)


画面遷移処理を追加します。


StoryBoardを開きます。
Save&Backボタンを右クリック(1ボタンマウスの場合、Controllキーを押しながらクリック)し、
4つ並んでいるアイコンの、一番右のアイコン(Exit)にドラッグ&ドロップします。




ReturnActionForSegue を選択します。




StoryBoardの右にソースコードDataViewController.mを表示させます
(右上の蝶ネクタイのようなアイコンを押すと画面が分割されます)。
4つ並んでいるアイコンの、右から2番目のアイコン(Tap Gesture Recognizer)を右クリックし、
メソッド viewTapped のドラッグ&ドロップします。



完成


以上で完成です。お疲れさまでした。

iPhone 日記アプリの作り方(1)画面、画面遷移

もくじページ
http://d.hatena.ne.jp/seika_m/20150822

プロジェクト作成


Xcodeのメニューから
File > New > Project を選択します。


iOS > Page-Based Application を選択してNext


Product Nameにファイル名を、
Organization Name にはあなたの名前、
Organization Identifier にはあなたのドメイン(WebサイトやGitHubのアドレスなど)、
Language は Objective-Cを、
Devices は Universal を
選択して Next


プロジェクトが作成されます
この状態で右上の再生ボタンを押すと
アプリが起動します。


ページをめくることができます。
ここに機能を追加していきます。



クラス追加


Table Viewのためのクラスを追加します


Xcodeのメニューから
File > New > File を選択します。


iOS > Cocoa Touch Class を選択してNext


Subclass of: で UITableViewController を選択してNext


Createを押下します。



日記データのクラスを追加します
Xcodeのメニューから
File > New > File を選択します。

iOS > Cocoa Touch Class を選択してNext


Subclass of: で NSObject を選択してNext


Createを押下します。



テーブルコントロール変更


一番左のナビゲーションエリアのMain.stroryBoardを選択します。


右下のオブジェクトからTabe View Controller を選んで、
左から3番目のエリアにドラッグ&ドロップします。


左から2番目のエリアで黄色いアイコンのTable View Controllerを選択します。
メニューの
Editor > Embed In > Navigation Controller を選択します。


Navigation Controller が追加されます


左から2番目のエリアでNavigation Controlle を選択して、
is Initial View にチェックを入れます。



左から2番目のエリアで黄色いアイコンのTable View Controllerを選択します。
Classのドロップダウンボタンを押して、TableViewController を選択します。



左から2番目のエリアでTable View Cellを選択します。
Identifier に articleCell と入力します。


Table View Cell から articleCell に変化します



Segue追加(ボタン)


右下のオブジェクトから Bar Button Item を選択して、
Table view の Navigation Controller エリアにドラック&ドロップします


IdentifierをAddに変更します
ボタンがプラスになります。


追加したボタンを右クリック(1ボタンマウスの場合、Controllキーを押しながらクリック)し、
茶色のRoot View Controlloer にドラッグ&ドロップします
(青い線が出てきます)。


Segue の中からPresent Modally を選びます。
するとSegue (画面の間をつなぐ矢印)ができます。


Segue を選択し、Identifierに addArticle を入力します



Segue追加(セル)


左から2番目のエリアでTable View Cellを選択します。
すると左から3番目のエリアでセルが青くなるので右クリック(1ボタンマウスの場合、Controllキーを押しながらクリック)し、
茶色のRoot View Controlloer にドラッグ&ドロップします
(青い線が出てきます)。
Segue の中からPresent Modally を選びます。


Segue を選択し、Identifierに addArticle を入力します



制約追加(Text View)


Data View Controller のLabel と View を削除します
(カーソルを合わせてDelete)


Data View に Text Viewを追加します。


Text Viewを選択し、下に4つ並んでいるボタンの左から2つ目を押します。


4つの点線をクリックして実線にします。
下のボックスに350, 他のボックスに30を入力してAdd 4 constraints を押します。
※先に実線にしてから、次に数値を入れます。そうでないとうまく動きません。


Text Viewを選択してから
下に4つ並んでいるボタンの左から3つ目を押し、Update Framesを押します。


Constraints が登録されている事を確認します(青い線で表示されます)。



制約追加(Text Field, Label, Button)


右下のエリアから
Text Field
を追加します


制約を追加します。
下のボックスに310, 左右のボックスに30を入力して Add 3 constraints を押します。


Text Field を選択してから
下に4つ並んでいるボタンの左から3つ目を押し、Update Framesを押します。


右下のエリアから
Label
を追加します


下のボックスに270, 左のボックスに30を入力して Add 2 constraints を押します。
下に4つ並んでいるボタンの左から3つ目を押し、Update Framesを押します。



右下のエリアから
Button
を追加します
Titleを Save&Back に変更します。


下のボックスに260, 右のボックスに30を入力して Add 2 constraints を押します。
下に4つ並んでいるボタンの左から3つ目を押し、Update Framesを押します。



Tap Gesture Recognizer追加


右下のエリアから
Tap Gesture Recognizer
を追加します
(すると画面上部にアイコンが追加されます。)



IBOutlet 追加


右上の蝶ネクタイのボタンを押します。
すると、Story Board画面の横にソースコードが表示されます。


Automatic と表示されているアイコンを Manual に変更し、
DataViewController.h を選択します。


Text View を右クリック(1ボタンマウスの場合、Controllキーを押しながらクリック)し、
ソースコードの@interface と @end の間にドラッグ&ドロップします。
Name に articleBody を入力して Connect を押下します。


同じように、Text Fieldも右クリックして、ソースコードにドラッグ&ドロップし、
Name に articleTitle を入力して Connect を押下します。


Labelは元からある
@property (strong, nonatomic) IBOutlet UILabel *dataLabel;
の上にドラッグ&ドロップします。



背景色変更


Viewの背景色を変更します。


Data View Controller の
Viewを選択し、Background を Group Table View Background Color に変更します。


Root View Controller の
Viewを選択し、Background を Light Gray Color に変更します。



動作確認


画面はここまででほとんど完成です。
再生ボタンを押すと動作を確認できます。



次はソースコードを変更していきます。
(あとで1度だけStrory Boardを使います。)

iPhone 日記アプリの作り方

Xcode + Objective-CiPhone 日記アプリを作ったので、その作り方をメモしておきます。


アプリ名:FlipDiary


作るアプリ:スワイプでページをめくる日記


機能:テーブルコントロールに日記の一覧が表示される。


右上の+ボタンで詳細画面に遷移して、新規日記を登録できる。
詳細画面では左にスワイプすることで前日の日記を見る事ができる
右にスワイプすることで次の日の日記を見る事ができる。


(1)画面、画面遷移作成
http://d.hatena.ne.jp/seika_m/20150823


(2)ソースコード
http://d.hatena.ne.jp/seika_m/20150824

Ruby on Rails を使ったWebサービスの作り方(6)herokuへのデプロイ


もくじページ
http://d.hatena.ne.jp/seika_m/20150815


まずテスト用の画像を削除します
これを行わないと、後で heroku run rake db:migrate が bash: rake: command not found のエラーになります

$ rails db
$ delete from rooms;
$ .exit
$ rm -r public/uploads/room


事前にherokuのユーザー登録とカードの認証(料金は無料です)が必要です。
ユーザー登録の参考サイト
http://developers.mobage.jp/blog/how-to-use-for-beginners-heroku
3. SSH鍵を設定します。
まで行って下さい。


ユーザー認証
https://heroku.com/verify


herokuにはgitでアップロードするので、リポジトリを作成します。

git init
git add .
git commit -a -m "Add Heroku"


Herokuにアプリを作成します

heroku create xxx(アプリ名)

アプリ名は他に使われていないものが必要です。今回は
heroku create home-test01-shimamura
とします。


以下のような表示がされます

Creating home-test01-shimamura... done, stack is cedar-14
https://home-test01-shimamura.herokuapp.com/ | https://git.heroku.com/home-test01-shimamura.git
Git remote heroku added
updating Heroku CLI...done. Updated to 3.41.4


https://home-test01-shimamura.herokuapp.com/
がサービスのアドレスになります。


デプロイします

git push heroku master


クラウドの画像をアップロードできるようにするアドオンをインストールします
(このアドオンを使用するために、カードの認証が必要になります)

heroku addons:create cloudinary


db migrateを行います

heroku run rake db:migrate


herokuのページを開きます

heroku open

Ruby on Rails を使ったWebサービスの作り方(5)その他ファイル


もくじページ
http://d.hatena.ne.jp/seika_m/20150815


以下ファイルは完成した物をコピーします。
assetsファイル
helpersファイル
controllersファイル
uploadersファイル
viewsファイル


https://github.com/fumio-shimamura/lovelivehome/tree/lesson01
からファイルをダウンロードして下さい。


lovelivehome-master>app>assets

home01>app>assets
に上書き


lovelivehome-master>app>controllers

home01>app>controllers
に上書き


lovelivehome-master>app>helpers

home01>app>helpers
に上書き


lovelivehome-master>app>uploaders

home01>app>uploaders
に上書き


lovelivehome-master>>app>views

home01>app>views
に上書き



ルーティング

home01>config>routes.rb を以下のように編集します

Rails.application.routes.draw do

  # root画面
  root   'welcome#index'
  # ユーザー新規登録画面
  get    'signup'  => 'users#new'
  # ログイン画面
  get    'login'   => 'sessions#new'
  # ログイン実行
  post   'login'   => 'sessions#create'
  # ログアウト
  delete 'logout'  => 'sessions#destroy'

  # ユーザー新規登録、照会
  resources :users   ,      only: [:new, :create, :show]
  # ログイン、ログアウト
  resources :sessions,      only: [:new, :create, :destroy]
  # フォロー、アンフォロー
  resources :relationships, only: [:create, :destroy]
  # 部屋の写真登録、削除、照会
  resources :rooms,         only: [:new, :create, :destroy, :show]

end

動作確認

$ rails s

でサーバーが起動します


webブラウザ
http://localhost:3000/
にアクセスします。


以下の動作を確認します。
・ユーザーを登録できること
・ログアウトできること
・ログインできること
・画像をアップロードできること
・画像を削除(ゴミ箱アイコンを押す)できること
・2つ目の画像をアップロードして詳細画面を見られる事
http://localhost:3000/rooms/2 が2つ目の画像の詳細画面になります)
・2人目のユーザーを登録して1人目のユーザーをフォローできる事
http://localhost:3000/users/1 が1人目のユーザーのページになります)

Ruby on Rails を使ったWebサービスの作り方(4)model 生成、変更とmigrationファイルへの追記


もくじページ
http://d.hatena.ne.jp/seika_m/20150815


ユーザーのモデルを生成します

$ rails generate model User name email password_digest

部屋(の写真)のモデルを生成します

$ rails generate model Room user:references image:string place:string detail01:string 

ユーザーの関連(フォロー)のモデルを生成します

$ rails generate model Relationship follower:references followed:references


home01>app>models>user.rbを以下のように変更します

class User < ActiveRecord::Base
  # emailを小文字にする
  before_save { self.email = email.downcase }
  # validation (入力チェック)
  # 名前は入力必須、50文字以下
  validates :name, presence: true, length: { maximum: 50 }
  # emailアドレスは入力必須、255文字以下、正規表現にマッチする、ユニークである
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  # パスワードを暗号化して保存する
  has_secure_password
  
  # ユーザーと部屋は1対多の関係
  has_many :rooms

  # ユーザーとfollowingは1対多の関係(1ユーザーが複数のユーザーをフォローする)
  has_many :following_relationships, class_name:  "Relationship", foreign_key: "follower_id", dependent: :destroy
  has_many :following_users, through: :following_relationships, source: :followed
   # ユーザーとfollowedは1対多の関係(1ユーザーは複数のユーザーにフォローされる)
  has_many :followed_relationships, class_name:  "Relationship", foreign_key: "followed_id", dependent: :destroy
  has_many :followed_users, through: :followed_relationships, source: :follower

  # 他のユーザーをフォローする
  def follow(other_user)
    following_relationships.create(followed_id: other_user.id)
  end

  # フォローを解除する
  def unfollow(other_user)
    following_relationships.find_by(followed_id: other_user.id).destroy
  end

  #  フォローしているか
  def following?(other_user)
    following_users.include?(other_user)
  end

end


home01>app>models>room.rbを以下のように変更します

class Room < ActiveRecord::Base
  # validation (入力チェック)
  # ユーザーIDは入力必須
  validates :user_id, presence: true
  # 画像ファイルは入力必須
  validates :image,   presence: true
  # detail01は40文字以下
  validates :detail01,    length: { maximum: 40 }

  # ユーザーと部屋は1対多の関係
  belongs_to :user

  # 画像ファイルをアップロードするための設定
  mount_uploader :image, RoomimageUploader
end


home01>app>models>Relationship.rb を以下のように変更します

class Relationship < ActiveRecord::Base
  # 参照先クラスはUser
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
end


home01>app > db > migrate > xxx_create_users.rb を以下のように変更します
(xxxの部分はシステムが生成した値です)
※t.index (DBのIndex)を追加

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :password_digest

      t.timestamps null: false

      t.index :email, unique: true # この行を追加
    end
  end
end


home01>app > db > migrate > xxx_create_relationship.rb を以下のように変更します

※foreign_key を削除
※t.index (DBのIndex)を追加

class CreateRelationships < ActiveRecord::Migration
  def change
    create_table :relationships do |t|
      t.references :follower, index: true  #foreign_key を削除
      t.references :followed, index: true  #foreign_key を削除

      t.timestamps null: false

      t.index [:follower_id, :followed_id], unique: true # この行を追加
    end
  end
end


home01>app > db > migrate > xxx_create_rooms.rb を以下のように変更します

※t.index (DBのIndex)を追加

class CreateRooms < ActiveRecord::Migration
  def change
    create_table :rooms do |t|
      t.references :user, index: true, foreign_key: true
      t.string :image
      t.string :place
      t.string :detail01

      t.timestamps null: false

      t.index [:user_id, :created_at] # この行を追加
    end
  end
end


db migrateします

$ rake db:migrate