Финал той самой истории.
Первая часть, вторая, третья, четвертая.
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 мне очень вовремя одолжили. Можно было с головой погрузиться в разработку.
Про Катю
В предыдущей части: Она очень позитивно отреагировала на то, что я вышел с ней на связь, согласилась встретиться. Потом сказала, что у неё всё плохо, подружка с которой она снимала квартиру съехала и что она из-за стрессов каждый день плачет, еще и уволиться решила. Я решил, что, когда мы встретимся, предложу ей переехать жить ко мне и ни о чем не париться.
В итоге Катя так и не приехала. Опять были какие-то отмазки. Закончилось тем, что она меня снова послала. На этот раз я не думал сразу уходить, т.к. чувствовал, что нужен ей. Но Катя слишком сильно хотела, чтобы я ушел и мне пришлось оставить её в покое. И пообещать больше никогда не звонить и не писать ей.
В итоге Катя так и не приехала. Опять были какие-то отмазки. Закончилось тем, что она меня снова послала. На этот раз я не думал сразу уходить, т.к. чувствовал, что нужен ей. Но Катя слишком сильно хотела, чтобы я ушел и мне пришлось оставить её в покое. И пообещать больше никогда не звонить и не писать ей.
Скомпилировалось и запустилось всё без особых проблем. Открыл в браузере и… ничего. Но зато если зайти по сети на 127.0.0.1:8089 то выдавало кошелек. Стало очевидным, что при нажатии кнопки home приложение переходит в какой-то спящий режим.
По аналогии с андроидом решил сделать сервис. Но, оказывается сервисы на ios невозможны. Максимум что можно сделать — это повисеть в бэкграунде 600 секунд. Так то оно, конечно, логично — борьба за сохранность заряда аккумулятора. В общем, пришлось изучать, как там вообще работают приложения в ios.
Создал простенькое приложение в xcode, кинул на тел, работает. Начал копать структуру файлов и параллельно искать что-то похожее в gomobile, нашел вот этот файлик. Узнал про NSLog, определил место, куда он выдает инфу
Помню свою радость, когда увидел строки в логе, которые выводило мое приложение. Это было круто, связь налажена, дальше будет проще. Для меня возможность писать и читать логи — это, наверное, самое важное при разработке приложения.
Про Машу
Снова стал искать девушку на сайтах знакомств и в ВК. Я забыл упомянуть, что держу себя в отличной физ. форме, т.к. дома есть куча блинов, 2 штанги, гантельные грифы, скамья и турник. И выгляжу на 20 с чем-то, хотя мне уже за 30. Довольно быстро нашел девушку, которая мне нравилась и которая хотела со мной встретиться.
Objectve-C я не знал, да и сейчас толком не знаю. Но было очевидно, что без понимания, как минимум, синтаксиса ничего не получится. Немного почитал уроки про Objectve-C, стало проще понимать код.
Погуглил про фоновый режим, выяснил, что надо в didFinishLaunchingWithOptions добавить вот такой код
// UIApplicationBackgroundFetchIntervalMinimum - чтобы наше приложение запустилось в бэкграунде при любом возможном случае
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
И добавить в info.plist
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
</array>
Gomobile генерит свой info.plist. Внести в него правки можно тут.
Про Машу
На первое свидание я опоздал минут на 10. Когда увидел Машу, то сразу подумал «Ухты, а мне везет», она была очень в моем вкусе. Мы гуляли по парку, катались на лодке, потом я сказал, что мне надо поесть белковой пищи, иначе мышцы расти не будут и повел к себе домой. Поев куриного мяса, пошли в спальню смотреть фильм. Но минут через 30 она сказала, что ей надо домой, т.к. она плохо себя чувствует из-за того, что еще не до конца вылечилась от простуды. Вызвал такси. Маша уехала.
webView
То, что в браузере всё работало было конечно круто, но этого хватало лишь на 3 минуты, ведь когда открывается браузер приложение идет в фоновый режим и через 3 минуты падает. Без webView тут никак. Довольно долго разбирался, куда и как вставить webView, чтобы оно отображалось. GUI-то нет, всё в текстовом файле надо писать, а учитывая, что с разработкой под IOS я был вообще не знаком, мне было очень тяжко
В итоге, конечно, всё получилось и оказалось крайне просто.
Про Машу
Затем в течение недели она говорила, что работает и нет времени встретиться, и увидеться мы сможем только в воскресенье и не раньше, чем через 2 недели. Я сказал, чтобы тогда просто приезжала ко мне после работы, живем то рядом, а видеться раз в неделю меня не устраивает. Она ответила, что подумает.
Через день написала, что боится ехать на ночь к малознакомому парню. Я сказал, что думал что она пропала с концами и уже чуть не начал назначать свидания другим девушкам на эти выходные. Она разозлилась, ругалась.
На следующий день отправил шутки ради смс-ку «Весь день на свиданках, катаюсь на лодке, в мозолях руки и не только». Шутку она не поняла, разозлилась пуще прежнего, пришлось объяснить, что мол шутка это, дома я весь день был, код писал.
Через день написала, что боится ехать на ночь к малознакомому парню. Я сказал, что думал что она пропала с концами и уже чуть не начал назначать свидания другим девушкам на эти выходные. Она разозлилась, ругалась.
На следующий день отправил шутки ради смс-ку «Весь день на свиданках, катаюсь на лодке, в мозолях руки и не только». Шутку она не поняла, разозлилась пуще прежнего, пришлось объяснить, что мол шутка это, дома я весь день был, код писал.
- (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))
}
Про Машу
Прислал к ней такси, встретил, поднялись ко мне, поужинали, посмотрели какой-то фильм. Время было уже позднее, надо было ложиться спать. Она сказала, что будет спать на гостевом диване, т.к. со мной в одной кровати она еще не готова. «Ну нет, так нет», постелил ей на диване. Через 5 минут заходит и говорит, что у неё «этого» еще никогда не было, но она очень хочет. Для меня это стало приятной неожиданностью. В общем, той ночью мы не спали.
В 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)];
}
Это чтобы при запуске у пользователя вылезло сообщение с запросом прав на использование уведомлений.
Про Машу
На 4-м свидании я предложил ей переехать ко мне. Маша согласилась. Заехал к ней в общагу и перевез вещи.
Заключение
На примере Dcoin можно понять, что почти любой человек может писать на GO приложения, которые будут работать на всех основых ОС, в том числе и на мобильных.
Про Машу и Катю
Прошло где-то пару недель. Поздний вечер, лежим с Машей на кровати, смотрим Интернов. Звонит Катя. Пьяная. Говорит, что просит у всех прощения, и что она наглоталась снотворного и через несколько часов умрет. Я растерялся, не знал что говорить. Попытался выяснить, где она находится, чтобы прислать к ней полицию и медиков. Потом написал её лучшей подружке, чтобы она сообщала её адрес и связалась срочно с Катей, она почему-то на захотела говорить адрес. Позвонил Кате, и услышал на заднем плане чей-то пьяный голос. Всё стало ясно, это блеф, она бухает со своей подружкой. На следующий день убедился, что с Катей всё в порядке, т.к. она была онлайн.
Сейчас уже 6-й месяц живу с Машей. Недавно завели кота.
Сейчас уже 6-й месяц живу с Машей. Недавно завели кота.
P.S.
1. 21 апреля едем в Нью-Йорк на выставку стартапов TechDay, если будете там же, велкам к нашему стенду.
2. В Dcoin сейчас можно получить бесплатные монеты (хватит на оплату инета на несколько месяцев).