Катя, Go, Dcoin и Android



    Продолжение той самой истории.

    Первая часть тут, вторая тут, третья тут.

    4,5 года назад я имел неосторожность начать писать свою криптовалюту на совсем неподходящем для этого дела языке — на PHP. В итоге, конечно, написал (я упрямый), но получился костыль на костыле и то, что оно вообще работало было просто какой-то магией.

    Сразу хочу предупредить, программер я самоучка-недоучка и пишу код, мягко сказать, неидеально.

    Началось всё с того, что я расстался с девушкой, по имени Катя и в этот же день (4 апреля 2015-го) решил изучить Go и переписать свою криптовалюту. Писать про Катю не под спойлерами не могу, т.к. хабр всё же для IT-шных статей, а не для любовных рассказов и суровые айтишники, которым интересна тема Go, могут просто не обращать внимание на спойлеры «про Катю».

    Итог 8 месяцев: приложение работает на Win (64/32), OSX(64/32), Linux(64/32), FreeBSD(64/32), Android, IOS.

    Общего кода ~73к строк, кода под разные ОС где-то несколько сотен строчек.

    40к — обработка/генерация блоков/тр-ий, 17.5к — контроллеры для интерфейса, 15.5к — шаблоны.

    Поддерживаются PostgreSQL, SQLite, MySQL.

    Тех, кто будет тестировать мое творение, предупреждаю — могут быть баги, и если у Вас есть время, черкните о них, пожалуйста, на darwin@dcoin.club или в личку на хабре. Пожелания и советы тоже приветствуются.

    В первых трех частях я рассказал про то, как в dcoin функционирует веб-сервер, про html/template, базы данных, плавное завершение приложения, шифрование и парсинг блоков.

    В этой статье я расскажу про работу с Go на Android.

    Начало


    Смешно сказать, но мой первый андроид появился у меня этим летом. До этого я просто не находил причин, чтобы заменить свою Nokia 1200. Купил дешевый ZTE за 3000 руб с 512 памяти и 2-я ядрами. Для тестирования самое то. И звонить с него тоже можно.

    Хотелось сделать компиляцию через github.com/golang/mobile в apk. Посмотрел мануалы, вроде всё просто. Почти сразу получилось скомпилировать бинарник и запустить его под рутом на андроиде. Обрадовался, что всё идет как по маслу и казалось, что через пару дней у меня будет apk, запустив который я увижу Dcoin.

    Собрать Apk оказалось не сложно. В принципе, всё что мне было нужно — это автоматически открыть в браузере 127.0.0.1:8089. Вот тут-то я забуксовал. Несколько дней гуглил и экспериментировал и всё чего смог добиться — это отрисовка картинки на которой я прошу пользователя открыть в браузере нужный хост.

    Решил зайти через aar. Т.е. добавить его как библиотеку в андроид-студио. И средствами студии уже открыть браузер или webview. Но sqlite упорно не хотело компилиться, оказалось что ошибка в компиляторе C и решения проблемы на тот момент не было (сейчас, кстати, уже есть).

    Про Катю
    (Окончание из предыдущей части): Написал ей в ВК, сказала, что тел дома забыла, а сейчас у подруги. Я написал, что подожду её. После чего получил «Не звони и не пиши мне больше!!!!». Вопросов задавать не стал, позвонил в соседнюю квартиру, попросил передать цветы Кате, когда она будет дома. Приехал домой, через несколько часов принял решение переписать Dcoin на Go.

    Через пару дней написал ей, что на несколько месяцев ухожу с головой в свой проект и попросил не беспокоить меня по пустякам.

    Через неделю от Кати пришла смс-ка «привет. ну как ты там?». Я не ответил. Через неделю еще одна «привет. как дела?». Я снова не ответил.


    GoNativeActivity


    В какой-то момент стало очевидно, что без этого волшебного файлика ничего не выйдет. Начал экспериментировать, внес несколько изменений, генерирую apk и ничего не меняется. Через пару дней не выдержал и решил написать одному из разработчиков gomobile, ответ пришел довольно быстро. Оказывается, после изменений в GoNativeActivity надо вызывать go generate github.com/c-darwin/mobile/cmd/gomobile, чтобы сгенерировался .dex файл и только после этого go install github.com/c-darwin/mobile/cmd/gomobile.

    Научившись править GoNativeActivity я получил огромные возможности. Нужно было лишь уметь писать на Java. А я не умел, и сейчас не умею. Но кое-что всё же смог сделать. Тут мой GoNativeActivity. Чуть позже понял, как создать свой AndroidManifest.xml, что дало еще больше возможностей, в итоге вместо работы в браузере я смог добиться работы в WebView, тут моя реализация вебвьюхи.

    Про Катю
    Еще примерно через неделю она написала, что ей срочно нужно 7 т.р. в долг, т.к. ей не хватает на оплату за квартиру. Я ответил «OK». На следующий день она приехала ко мне домой.

    Уведомления


    Мне захотелось сделать уведомления, когда приходят деньги или поступает входящий запрос на обмен монет на фиат. После гугления и изучения stackoverflow получился такой код:

    public void notif(String title, String text) {
    
      	  Intent intent = new Intent("org.golang.app.MainActivity");	    
    
    	  NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
    	  // с этой иконкой пришлось повозиться, нижу расскажу
    	  mBuilder.setSmallIcon(R.drawable.icon);
    	  mBuilder.setContentTitle(title);
    	  mBuilder.setContentText(text);
    	          
    	  Intent resultIntent = new Intent(this, MainActivity.class);
    	  TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    	  stackBuilder.addParentStack(MainActivity.class);
    
    	  // Adds the Intent that starts the Activity to the top of the stack
    	  stackBuilder.addNextIntent(resultIntent);
    	  PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
    	  mBuilder.setContentIntent(resultPendingIntent);
    
    	  NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        
    	  // notificationID allows you to update the notification later on.
    	  mNotificationManager.notify(2, mBuilder.build());
    
        }   
    

    Осталось только понять, как этот notif дергать из Go. Вот тут я застрял еще на недельку. Оказалось, что надо использовать некого зверя под названием JNI. Получается что-то вроде такой конструкции: Go вызывает C, который запускает Java-машину и дергает через неё мой notif. Ужас. Особенно учитывая, что в C, я также как и в Java, почти полный ноль.

    Короче, после долгих мучений я смог таки написать рабочий код и даже понять, что в нем происходит:

    package notif
    
    /*
    #cgo LDFLAGS: -llog -landroid
    #include <android/log.h>
    #include <jni.h>
    #include <stdlib.h>
    
    #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go/fatal", __VA_ARGS__)
    
    void notif_manager_init(void* java_vm, void* ctx, char* title, char* text) {
    	JavaVM* vm = (JavaVM*)(java_vm);
    	JNIEnv* env;
    	int err;
    	int attached = 0;
    
    	err = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6);
    	if (err != JNI_OK) {
    		if (err == JNI_EDETACHED) {
    			// присоединяемся к JM
    			if ((*vm)->AttachCurrentThread(vm, &env, 0) != 0) {
    				LOG_FATAL("cannot attach JVM");
    			}
    			attached = 1;
    		} else {
    			LOG_FATAL("GetEnv unexpected error: %d", err);
    		}
    	}
    	
    	// преобразуем в jstring наш title
    	jstring javaTitle = (jstring)(*env)->NewStringUTF(env, (const char *)title);
    	// преобразуем в jstring наш text
    	jstring javaText = (jstring)(*env)->NewStringUTF(env, (const char *)text);
    		
    	//указатель на класс, к которому относится объект
    	jclass cls = (*env)->GetObjectClass(env, ctx);
    	// идентификатор метода.Ljava/lang/String;Ljava/lang/String - тип передаваемых данных и V(Void) - возвращаемых
    	jmethodID nJmethodID = (*env)->GetMethodID(env, cls, "notif", "(Ljava/lang/String;Ljava/lang/String;)V");
    	// вызываем сам метод
    	(jstring)(*env)->CallObjectMethod(env, ctx, nJmethodID, javaTitle, javaText);
    		
    
    	if (attached) {
    		// отсоединяемся от JM
    		(*vm)->DetachCurrentThread(vm);
    	}
    }
    */
    import "C"
    import (
    	"github.com/c-darwin/mobile/internal/mobileinit"
    )
    
    
    func SendNotif(title string, text string) {
    	ctx := mobileinit.Context{}
    	C.notif_manager_init(ctx.JavaVM(), ctx.AndroidContext(), C.CString(title), C.CString(text))
    }
    

    По аналогии у меня получился пакет get_files_dir.go который получает рабочую директорию.

    Про Катю
    Я не знаю, что у неё было в голове, наверное думала, что я буду к ней приставать. Весь вечер она была какой-то странной. Я был холоден и старался избегать любых прикосновений к ней. Мы поели, попили чаю. Катя сказала, что ей надо домой. Я вызвал такси.
    Когда провожал её до такси спросил:

    — Мы ведь не вместе да? Т.е. я могу делать что захочу?
    Она: — В смысле «что захочу»? нет, мы вместе (пододвигается ко мне)
    Я: — Ну у нас же не было первого свидания, мы еще не начали всё с начала.
    Она: — Так вот было же только что.
    Я: — Какое же это свидание, ты просто за деньгами приехала.

    Мы уже стояли у дверей такси, я её усадил, расплатился с водителем, она уехала.

    На Go получился вот такой код для вызова уведомления:

    // +build android
    
    package sendnotif
    
    import (
    	"github.com/c-darwin/mobile/notif"
    )
    
    func SendMobileNotification(title, text string) {
    	notif.SendNotif(title, text)
    }
    

    Про Катю
    Утром зазвонил телефон, это была Катя. Я не поднял трубку.

    Сервис


    Заметил, что веб-серер стал постоянно падать. Работать с кошельком было невозможно. Погуглил, понял, что надо делать сервис. На этот раз сложностей было уже не так много, исходник тут. ShortcutIcon() создает иконку на рабочем столе.

    Про Катю
    На следующий день она прислала смс-ку «привет. я вчера звонила, ты не взял трубку». Я не стал отвечать.

    Доступ к иконке


    При появлении уведомлений нужно указать иконку. Пришлось разбираться как в android устроена работа с ресурсами. Примерно понял, что нужно сгенерировать R.jar и подключить его при генерации dex-файла.

    Погуглил, как генерить java файлы, получилась такая команда:

    aapt package -v -f -J /home/z/go-projects/src/github.com/c-darwin/dcoin-go/ -S /home/z/go-projects/src/github.com/c-darwin/dcoin-go/res/ -M /home/z/go-projects/src/github.com/c-darwin/dcoin-go/AndroidManifest.xml -I /home/z/android-sdk-linux/platforms/android-22/android.jar
    

    Полученный R.java помещаем в R/org/golang/app/:

    mv R.java /home/z/go-projects/src/github.com/c-darwin/dcoin-go/R/org/golang/app/
    

    И генерируем R.jar:

    cd R && jar cfv /home/z/go-projects/src/github.com/c-darwin/dcoin-go/R.jar 
    

    Генерим неподписанный apk:

    aapt package -v -f -J /home/z/go-projects/src/github.com/c-darwin/dcoin-go/ -S /home/z/go-projects/src/github.com/c-darwin/dcoin-go/res/ -M /home/z/go-projects/src/github.com/c-darwin/dcoin-go/AndroidManifest.xml -I /home/z/android-sdk-linux/platforms/android-22/android.jar -F unsigned.apk
    

    Про Катю
    Через неделю она написала, что получила з.п. и хочет скинуть мне на карту деньги. Я ни чего не ответил. Через несколько дней она написала «привет. как дела?». Я снова игнорировал.

    Вытаскиваем в корень resources.arsc:

    unzip unsigned.apk -d apk && mv apk/resources.arsc .
    

    Дальше нужно подправить gendex.go из gomobile:

    cmd := exec.Command(
    		"javac",
    		"-source", "1.7",
    		"-target", "1.7",
    		"-bootclasspath", platform+"/android.jar",
    		"-classpath", "/home/z/go-projects/src/github.com/c-darwin/dcoin-go/R.jar:"+androidHome+"/extras/android/m2repository/com/android/support/support-v4/22.2.1/support-v4-22.2.1-sources.jar",
    		"-d", tmpdir+"/work",
    	)
    

    Про Катю
    Еще примерно через неделю я наконец запустил Dcoin на нодах и увидев, как идет генерации блоков и как они летают между нодами, наполняя базы данных. Мне показалось, что это можно считать завершением моего временного отшельничества и я написал Кате.

    Генерируем новый Dex:

    ANDROID_HOME=/home/z/android-sdk-linux go generate github.com/c-darwin/mobile/cmd/gomobile/ 
    

    Затем бинарник самого gomobile:

    go install github.com/c-darwin/mobile/cmd/gomobile/ 
    

    И наконец получаем наш apk:

    CGO_ENABLED=1 GOOS=android ANDROID_HOME=/home/z/android-sdk-linux gomobile build -v github.com/c-darwin/dcoin-go
    

    В итоге, у меня получился вот такой bash скрипт для генерации apk:

    ./bindata.sh
    echo "######## generate R.java ########"
    aapt package -v -f -J /home/z/go-projects/src/github.com/c-darwin/dcoin-go/ -S /home/z/go-projects/src/github.com/c-darwin/dcoin-go/res/ -M /home/z/go-projects/src/github.com/c-darwin/dcoin-go/AndroidManifest.xml -I /home/z/android-sdk-linux/platforms/android-22/android.jar
    mv R.java /home/z/go-projects/src/github.com/c-darwin/dcoin-go/R/org/golang/app/
    echo "######## generate R.jar ########"
    cd R
    jar cfv /home/z/go-projects/src/github.com/c-darwin/dcoin-go/R.jar .
    cd ../
    echo "######## generate unsigned.apk ########"
    aapt package -v -f -J /home/z/go-projects/src/github.com/c-darwin/dcoin-go/ -S /home/z/go-projects/src/github.com/c-darwin/dcoin-go/res/ -M /home/z/go-projects/src/github.com/c-darwin/dcoin-go/AndroidManifest.xml -I /home/z/android-sdk-linux/platforms/android-22/android.jar -F unsigned.apk
    echo "######## extract resources.arsc ########"
    unzip unsigned.apk -d apk
    mv apk/resources.arsc .
    rm -rf apk unsigned.apk
    ANDROID_HOME=/home/z/android-sdk-linux go generate github.com/c-darwin/mobile/cmd/gomobile/ 
    go install github.com/c-darwin/mobile/cmd/gomobile/ 
    CGO_ENABLED=1 GOOS=android ANDROID_HOME=/home/z/android-sdk-linux gomobile build -v github.com/c-darwin/dcoin-go
    

    Про Катю
    Она очень позитивно отреагировала на то, что я вышел с ней на связь, согласилась встретиться. Потом сказала, что у неё всё плохо, подружка с которой она снимала квартиру съехала и что она из-за стрессов каждый день плачет, еще и уволиться решила. Я решил, что, когда мы встретимся, предложу ей переехать жить ко мне и ни о чем не париться.

    Заключение


    В следующей, заключительной статье я расскажу про gomobile и IOS. И, наконец, будет финал про Катю.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 46
    • +1
      Ещё одна часть и будет финал. Вангую, что будет хэппиенд)
      • +3
        Хэппиенд будет, но не полный )

        Из статьи упоминание про вакансию почему-то исчезло, видно правилами запрещено.
        Напишу тут. Ищу Go-программистов в команду на хорошую з.п.
        • +12
          Хорошую з.п. в Dcoin'ах?
          • +2
            В рублях, но можно и в долларах. Недавно появился инвестор, который выделил 20 млн руб. на развитие Dcoin.
            • +16
              Катя?
              • +2
                Про Катю
                Но ведь у неё не было даже 7 тыс. на оплату квартиры?
                • +3
                  Про Катю
                  Вы не поняли, это был хитрый ход. Нам его не понять.
      • +3
        На самом интересном месте! Как так можно???
        • +23
          > Я решил, что, когда мы встретимся, предложу ей переехать жить ко мне и ни о чем не париться.

          Вот начиная с этого момента начнутся настоящие проблемы. Знаем, проходили :)

          Историю про Катю не удобно читать, предлагаю код отправить под спойлеры, а Катю на передний план :)
          • +13
            Это ж хабр, тут так нельзя. Код важнее Кать, иначе на geektimes перенесут.
          • +4
            Только мне кажется что развод асинхронный и идет через сокеты, тк постоянно кодировка пакетов меняется и они не допонимают друг друга?
            Финал будет очень интересным. У девушки самый тупой развод на слезы и сопли. Парень держится молодцом, но вот эта «мы еще вместе» после такого «Динамо» открывает что творится у него в сердце =)

            Но вот отношений на жалости и «поживи у меня без проблем» вот как-то оно очень не оптимистично. Девочка добилась своего, есть парень с квартирой в москве… Вот только не похоже что бы она это могла оценить. В общем Вангуем и ждем =)
            • +1
              И все же это самый офигенная «не техническая» статья в разделе техники и IT =)))
            • +11
              Посмотрим как эвалюционирует серия статей про Go на основе названий:

              1) Как я 8 месяцев переписывал свою криптовалюту с PHP на Go. Часть 1
              2) Как я 8 месяцев переписывал свою криптовалюту с PHP на Go. Часть 2
              3) Как я 8 месяцев переписывал Dcoin на Go… про Катю, в общем
              4) Катя, Go, Dcoin и Android
              5) Про Катю

              Ясненько, понятненько.
              • +3
                Ну такой стресс у автора. Мысли все в одну точку скатились.

                Хотя можно рассудить по другому. Как с окончанием проекта у вас появляется время на девушек и другие дела =)
                • +4
                  Автор потакает запросам сообщества про «Больше Кати, меньше кода». Ну и, в общем-то, правильно делает.
                  P.S.: думаю, приписку «Программер, одержимый идеей децентрализации денег» скоро нужно будет менять на «Молодой человек той самой Кати, программер, одержимый идеей децентрализации денег». Ну или просто «Парень Кати» или «Бывший парень Кати», пока не ясно.
                • 0
                  КДПВ ведёт на страницу, скрытую в черновики, это специально?
                • –8
                  Я оставлю это тут )) https://www.youtube.com/watch?v=8g1-zV6yDmw
                • +11
                  Я один читал только про Катю?
                • 0
                  Предлагаю общественности высказывать идеи про финальную часть. Про Катю, естественно. С проектом понятно что все взлетит.
                  • +7
                    Смешно сказать, но мой первый андройд появился

                    За что Вы его так?
                  • +5
                    Мне показалось, что это можно считать завершением моего временного отшельничества и я написал Кате.

                    Я решил, что, когда мы встретимся, предложу ей переехать жить ко мне и ни о чем не париться.

                    Сдался мужик, а так хорошо ее отшивал.
                    • 0
                      Вот тут-то и будет "Empire strikes back"...
                    • 0
                      Что-то не запускается ваш Dcoin под Win64,
                      пишет 01:34:00.813 dcoin.go:206 Start [ERRO] OldFileName [2.0.1b4]
                      • 0
                        Спасибо за баг-репорт, сейчас разберемся, исправим. Но лучше, наверное, в личку такое писать.
                      • +2
                        Можно нескромный вопрос. Вы сами искали инвестора или он Вас сам нашел по статьям на хабре?
                      • +4
                        «Новые правила. Секреты успешных отношений для современных девушек»

                        Автор усвоил на отлично!
                        • +1
                          Жмем Ctrl+Shift+C, вводим:
                          jQuery('.post_show .spoiler_text').map(function() { return $(this).text() }).toArray().join('\n ');
                          

                          Наслаждаемся рассказом :)
                          • 0
                            Новое направление в литературе — фильтр on-demand :)
                          • +1
                            Чувак, попомни мои слова. С этой Катей ничего хорошего не получится. Шли её в пень.
                            • 0
                              Ну есть вероятность, что в конце она приходит с тремя фотомоделями и говорит — ты выдержал испытание, вот тебе награда!
                            • +1
                              Блин опять так долго ждать, мне кажется я "игры престолов" так не жду как рассказ про Катю.
                              • +3
                                удивительно, что я об этом еще вспоминаю, но все же, где продолжение?!
                                • +2
                                  каждый день захожу к автору в профиль посмотреть не вышла ли новая "серия" )
                                  • 0
                                    Прошу прощения, что так долго не пишу. После получения инвестиций времени стало совсем не хватать :( Постараюсь в ближайшие 2 недели выложить последнюю часть.
                                    • 0
                                      Да уж, Вы не забывайте, а-то я уже хотел в личку писать, спрашивать как дела с Катей) Блин, это как реалити-шоу смотреть!)
                                      • 0
                                        Подсадили нас на Катю :) Того гляди незаметно еще на что-то подсадят.
                                        • +1
                                          Ахах, и не говорите! Я вообще только с третьей статьи понял, что автор пишет какой-то скрипт :DDD
                                      • 0
                                        Можно спросить: вы получили инвестиции под этот проект?

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.