srcCompatにpng画像を設定してもAndroidStudio上では表示されるけれども、実機で表示されないっぽい長い

普段使わないAndroidのImageButtonを使って軽くハマったのでメモ

AndroidStudioでImageButtonを追加した際に、リソース選択のダイアログが出たので
適当にAndroid標準搭載?の「ic_menu_camera」を選択したらAndroidStudio上では表示されてるのに実機上で表示されなかった。

textで見てみると「app:srcCompat="@android:drawable/ic_menu_camera"」の記述が、、、srcCompat?
調べてみるSVG用の設定っぽいので、png画像に適用しても実機じゃ表示されないってことぽい。
android:src="@android:drawable/ic_menu_camera"」に書き換えたら普通に実機でも表示されました。

「こくばん」という名のLINE BOTを作成しました。

LINEの「Messaging API」の勉強を兼ねて、LINE BOTを作成しました。

「こくばん」は、ユーザーが発言した言葉を黒板調の画像に書き込んで行くBOTです。

グループトークなどで、色々書き込んで楽しんでもらうことを想定してます。

追記されていきます。

画像もそれっぽくなるようにしてみました。

「こくばん」は以下のリンクから友達登録できます。
友だち追加



今回は「さくらインターネット」さんの「さくらのレンタルサーバ・スタンダード」環境上にPHPで、主にGDライブラリを用いて作成しました。

BOT API Trial」のころと違い、使いやすいSDKが用意されていたので利用させて頂きました。


github.com


せっかくなので「LINE BOT AWARDS」にエントリーしました。


botawards.line.me

開発メモ

PHP用のSDKをcomposerを用いて利用

composer.json

{
    "require": {
        "linecorp/line-bot-sdk": "*.*"
    }
}
メインロジック基底クラス
<?php
namespace Game\ResTask;


use Game\Json\Res\LineResponseJson;
use LINE\LINEBot;
use LINE\LINEBot\Constant\HTTPHeader;
use LINE\LINEBot\HTTPClient\CurlHTTPClient;
use UnexpectedValueException;

/**
 * Class LineResponseTask
 * @package Game\ResTask
 */
abstract class LineResponseTask
{
    /** @var string $channel_token Channel Access Token */
    private $channel_token;
    /** @var string $channel_secret Channel Secret */
    private $channel_secret;

    /**
     * LineResponseTask constructor.
     * @param $channel_token
     * @param $channel_secret
     */
    public function __construct($channel_token, $channel_secret)
    {
        $this->channel_token = $channel_token;
        $this->channel_secret = $channel_secret;
    }

    /**
     * @param LINEBot $line_bot
     * @param LINEBot\Event\BaseEvent[] $events
     * @return mixed
     */
    protected function beforeRun(LINEBot $line_bot, Array $events = [])
    {
        return $line_bot;
    }

    /**
     * @param LINEBot $line_bot
     * @param LINEBot\Event\BaseEvent[] $events
     * @return mixed
     */
    abstract protected function run(LINEBot $line_bot, Array $events = []);

    /**
     * @param LineResponseJson $res_json
     * @return LineResponseJson
     */
    protected function afterRun(LineResponseJson $res_json)
    {
        return $res_json;
    }

    /**
     * @return mixed
     */
    public function main()
    {
        $line_bot = new LINEBot(new CurlHTTPClient($this->channel_token), ['channelSecret' => $this->channel_secret]);
        $body = file_get_contents("php://input");
        $signature = $_SERVER['HTTP_' . HTTPHeader::LINE_SIGNATURE];
        /** @var LINEBot\Event\BaseEvent[] $events */
        $events = $line_bot->parseEventRequest($body, $signature);

        $line_bot = $this->beforeRun($line_bot, $events);
        $res_json = $this->run($line_bot, $events);
        if (empty($res_json)) {
            throw new UnexpectedValueException('Responseなし');
        }
        $res_json = $this->afterRun($res_json);

        return $res_json;
    }
}
メインロジッククラス
<?php
namespace Game\ResTask\User;


use Exception;
use Game\Json\Res\LineResponseJson;
use Game\ResTask\LineResponseTask;
use Game\StoryToImage\MoldingImage\NormalMoldingImage;
use Game\StoryToImage\MoldingText\NormalMoldingText;
use LINE\LINEBot;
use LINE\LINEBot\Event\PostbackEvent;
use LINE\LINEBot\MessageBuilder\ImageMessageBuilder;

/**
 * Class StoryToImage
 * @package Game\ResTask\User
 */
class StoryToImage extends LineResponseTask
{
    /**
     * @param LINEBot $line_bot
     * @param LINEBot\Event\BaseEvent[]|LINEBot\Event\MessageEvent[] $events
     * @return mixed
     * @throws Exception
     */
    protected function run(LINEBot $line_bot, Array $events = [])
    {
        foreach ($events as $event) {
            switch ($event->getType()) {
                case 'message':
                    switch ($event->getMessageType()) {
                        case 'text':
                            /** @var $event LINEBot\Event\MessageEvent\TextMessage */
                            $molding_text = new NormalMoldingText($event->getEventSourceId(), $event->getText());
                            $image_url = $molding_text->image_file_manager->getImageUrl();
                            $image_message_builder = new ImageMessageBuilder($image_url, $image_url);
                            $line_bot->replyMessage($event->getReplyToken(), $image_message_builder);
                            break;

                        case 'image':
                            $response = $line_bot->getMessageContent($event->getMessageId());
                            if ($response->isSucceeded()) {
                                $image_resource = imagecreatefromstring($response->getRawBody());
                                $molding_text = new NormalMoldingImage($event->getEventSourceId(), $image_resource);
                                $image_url = $molding_text->image_file_manager->getImageUrl();
                                $image_message_builder = new ImageMessageBuilder($image_url, $image_url);
                                $line_bot->replyMessage($event->getReplyToken(), $image_message_builder);

                            } else {
                                // error処理
                            }
                            break;
                        default:
                            break;
                    }

                    break;
                case 'postback':
                    /** @var PostbackEvent $event */
                    $query = $event->getPostbackData();
                    break;
                default:
                    break;
            }
        }

        $res_json = new LineResponseJson();

        return $res_json;
    }
}
メインロジック実行クラス
<?php
namespace Game\ResTask;

use Exception;
use Game\Json\Res\LineResponseJson;

/**
 * Class LineResponseTaskExecutioner
 * @package Game\ResTask
 */
class LineResponseTaskExecutioner
{
    public static function Exec(LineResponseTask $res_task)
    {
        /** @var LineResponseJson $res_json */
        $res_json = new LineResponseJson();
        try {
            $res_json = $res_task->main();
        } catch (Exception $e) {
            // 例外処理
        }

        $res_json->outPut();
    }
}
エンドポイント
<?php
use Game\ResTask;

require_once dirname(__DIR__) . '/../../../project/line_test_bot/vendor/autoload.php';

$channel_token = '適宜チャンネルトークン';
$channel_secret = '適宜チャンネルシークレット';
$res_task = new ResTask\User\StoryToImage($channel_token, $channel_secret);
ResTask\LineResponseTaskExecutioner::Exec($res_task);
改善点

画像を回転させる場合に、回転前と回転後の間をうまく透過できない。(新しい画像を奥に描画することで妥協している)
フォントファイルを利用した絵文字対応。
時間が取れれば、DB管理したい。
アイコンが欲しい。

その他

質問など頂ければ、知っていることは全て答えます。
おもしろいLINE BOTがたくさん出るといいなー