Заключительная часть серии статей про мой опыт перехода с PHP на Go.
Первая часть, вторая, третья, четвертая.
4,5 года назад я имел неосторожность начать писать свою криптовалюту на совсем неподходящем для этого дела языке — на PHP. В итоге, конечно, написал (я упрямый), но получился костыль на костыле и то, что оно вообще работало было просто какой-то магией.
Сразу хочу предупредить, программер я самоучка-недоучка и пишу код, мягко сказать, неидеально.
Началось всё с того, что я расстался с девушкой, по имени Катя и в этот же день (4 апреля 2015-го) решил изучить Go и переписать свою криптовалюту. Писать про Катю не под спойлерами не могу, т.к. хабр всё же для IT-шных статей, а не для любовных рассказов и суровые айтишники, которым интересна тема Go, могут просто не обращать внимание на спойлеры «про Катю» и «про Машу».
Итог 8 месяцев: приложение работает на Win, OSX, Linux, FreeBSD, Android, IOS
Общего кода ~73к строк, кода под разные ОС где-то несколько сотен строчек.
40к — обработка/генерация блоков/тр-ий, 17.5к — контроллеры для интерфейса, 15.5к — шаблоны.
Поддерживаются PostgreSQL, SQLite, MySQL.
Тех, кто будет тестировать мое творение, предупреждаю — могут быть баги, и если у Вас есть время, черкните о них, пожалуйста, на darwin@dcoin.club или в личку на хабре. Пожелания и советы тоже приветствуются.
В первых четырех частях я рассказал про то, как в dcoin функционирует веб-сервер, про html/template, базы данных, плавное завершение приложения, шифрование и парсинг блоков, Android-приложение.
В этой части я расскажу про компиляцию под IOS.
Начало
Первой сложностью было то, что у меня не было сертификата разработчика. А без него скомпилировать приложение не получалось. Айфона у меня тоже не было, также как и Мака. Дня 3 возился с установкой osx на virualbox, в итоге смог поставить только на vmware и наладить сеть с virtualbox, чтобы в консоле работать.
Выяснил, что в моему счастью, в xcode 7 появилась возможность компилить приложения с фришным сертификатом, который может создать любой желающий. И айфон 4s мне очень вовремя одолжили. Можно было с головой погрузиться в разработку.
Написал ей в ВК, сказала, что тел дома забыла, а сейчас у подруги. Я написал, что подожду её. После чего получил «Не звони и не пиши мне больше!!!!». Вопросов задавать не стал, позвонил в соседнюю квартиру, попросил передать цветы Кате, когда она будет дома. Приехал домой, через несколько часов принял решение переписать Dcoin на Go.
Через пару дней написал ей, что на несколько месяцев ухожу с головой в свой проект и попросил не беспокоить меня по пустякам.
Через неделю от Кати пришла смс-ка «привет. ну как ты там?». Я не ответил. Через неделю еще одна «привет. как дела?». Я снова не ответил.
Еще примерно через неделю она написала, что ей срочно нужно 7 т.р. в долг, т.к. ей не хватает на оплату за квартиру. Я ответил «OK». На следующий день она приехала ко мне домой.
Я не знаю, что у неё было в голове, наверное думала, что я буду к ней приставать. Весь вечер она была какой-то странной. Я был холоден и старался избегать любых прикосновений к ней. Мы поели, попили чаю. Катя сказала, что ей надо домой. Я вызвал такси.
Когда провожал её до такси спросил:
— Мы ведь не вместе да? Т.е. я могу делать что захочу?
Она: — В смысле «что захочу»? нет, мы вместе (пододвигается ко мне)
Я: — Ну у нас же не было первого свидания, мы еще не начали всё с начала.
Она: — Так вот было же только что.
Я: — Какое же это свидание, ты просто за деньгами приехала.
Мы уже стояли у дверей такси, я её усадил, расплатился с водителем, она уехала.
Утром зазвонил телефон, это была Катя. Я не поднял трубку.
На следующий день она прислала смс-ку «привет. я вчера звонила, ты не взял трубку». Я не стал отвечать.
Через неделю она написала, что получила з.п. и хочет скинуть мне на карту деньги. Я ни чего не ответил. Через несколько дней она написала «привет. как дела?». Я снова игнорировал.
Еще примерно через неделю я наконец запустил Dcoin на нодах и увидев, как идет генерации блоков и как они летают между нодами, наполняя базы данных. Мне показалось, что это можно считать завершением моего временного отшельничества и я написал Кате.
Она очень позитивно отреагировала на то, что я вышел с ней на связь, согласилась встретиться. Потом сказала, что у неё всё плохо, подружка с которой она снимала квартиру съехала и что она из-за стрессов каждый день плачет, еще и уволиться решила. Я решил, что, когда мы встретимся, предложу ей переехать жить ко мне и ни о чем не париться.
Скомпилировалось и запустилось всё без особых проблем. Открыл в браузере и… ничего. Но зато если зайти по сети на 127.0.0.1:8089 то выдавало кошелек. Стало очевидным, что при нажатии кнопки home приложение переходит в какой-то спящий режим.
По аналогии с андроидом решил сделать сервис. Но, оказывается сервисы на ios невозможны. Максимум что можно сделать — это повисеть в бэкграунде 600 секунд. Так то оно, конечно, логично — борьба за сохранность заряда аккумулятора. В общем, пришлось изучать, как там вообще работают приложения в ios.
Создал простенькое приложение в xcode, кинул на тел, работает. Начал копать структуру файлов и параллельно искать что-то похожее в gomobile, нашел вот этот файлик. Узнал про NSLog, определил место, куда он выдает инфу
Помню свою радость, когда увидел строки в логе, которые выводило мое приложение. Это было круто, связь налажена, дальше будет проще. Для меня возможность писать и читать логи — это, наверное, самое важное при разработке приложения.
Objectve-C я не знал, да и сейчас толком не знаю. Но было очевидно, что без понимания, как минимум, синтаксиса ничего не получится. Немного почитал уроки про Objectve-C, стало проще понимать код.
Погуглил про фоновый режим, выяснил, что надо в didFinishLaunchingWithOptions добавить вот такой код
// UIApplicationBackgroundFetchIntervalMinimum - чтобы наше приложение запустилось в бэкграунде при любом возможном случае
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
И добавить в info.plist
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
Gomobile генерит свой info.plist. Внести в него правки можно тут.
webView
То, что в браузере всё работало было конечно круто, но этого хватало лишь на 3 минуты, ведь когда открывается браузер приложение идет в фоновый режим и через 3 минуты падает. Без webView тут никак. Довольно долго разбирался, куда и как вставить webView, чтобы оно отображалось. GUI-то нет, всё в текстовом файле надо писать, а учитывая, что с разработкой под IOS я был вообще не знаком, мне было очень тяжко
В итоге, конечно, всё получилось и оказалось крайне просто.
Через день написала, что боится ехать на ночь к малознакомому парню. Я сказал, что думал что она пропала с концами и уже чуть не начал назначать свидания другим девушкам на эти выходные. Она разозлилась, ругалась.
На следующий день отправил шутки ради смс-ку «Весь день на свиданках, катаюсь на лодке, в мозолях руки и не только». Шутку она не поняла, разозлилась пуще прежнего, пришлось объяснить, что мол шутка это, дома я весь день был, код писал.
- (void)viewDidLoad
{
// в фоновом потоке спим 3 сек, чтобы веб-сервер мог успеть запуститься, к БД подключиться и пр.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:3.0f];
// Переходим к выполнению кода в главном потоке
dispatch_async(dispatch_get_main_queue(), ^{
// собвственно сам webView
self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSMutableURLRequest * request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1:8089"]];
self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.webView.scrollView.bounces = NO;
self.webView.scalesPageToFit = NO;
self.view = self.webView;
self.webView.delegate = self;
[self.webView loadRequest:request];
});
});
[super viewDidLoad];
}
В интерфейс ViewController надо добавить наш webView
@interface ViewController : UIViewController<UIWebViewDelegate,UIScrollViewDelegate,UITextFieldDelegate>
{
IBOutlet UIWebView *webView;
.....
}
@property(nonatomic,retain)UIWebView *webView;
Уведомления
«Раз всё так просто, то надо сделать и уведомления» — подумал я.
Objectiv-C код пришлось внедрять в Go
// +build darwin
// +build arm arm64
package sendnotif
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework GLKit -framework UIKit
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
void
ShowMessM(char* title, char* text) {
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertTitle = [NSString stringWithUTF8String:title];
localNotification.alertBody = [NSString stringWithUTF8String:text];
localNotification.timeZone = [NSTimeZone systemTimeZone];
localNotification.applicationIconBadgeNumber = 1;
localNotification.repeatInterval = NSCalendarUnitMinute;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[localNotification release];
}
*/
import "C"
func SendMobileNotification(title, text string) {
C.ShowMessM(C.CString(title), C.CString(text))
}
В Go коде использовать так: sendnotif.SendMobileNotification(«Заголовок», «Текст уведомления»)
И в didFinishLaunchingWithOptions надо добавить:
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
Это чтобы при запуске у пользователя вылезло сообщение с запросом прав на использование уведомлений.
Заключение
На этом я заканчиваю серию статей про свой опыт перехода с PHP на Go. Надеюсь мой материал был кому-то полезен. Если будут вопросы про кроссплатформенную разработку на Go, пишите в личку, помогу.
Сейчас уже 6-й месяц живу с Машей. Недавно завели кота.
Автор: c-darwin