Recientemente decidí intentar implementar la idea de cómo compartir una ubicación a través de la API de VK con amigos en modo casi en tiempo real. El resultado fue una aplicación Qt multiplataforma para iOS / Android, una aplicación web para VKontakte y un par de solicitudes de extracción para VK API. En este artículo, me gustaría compartir algunos puntos de implementación no obvios que pueden ser de interés para alguien. Entonces, interesado, por favor pregunte por el gato.
¿Por qué lo necesitaba en absoluto?
Tarde o temprano, los niños crecen. La verdad banal. Entonces, mi hija de diez años dijo un día: "Papá, no me lleves más en auto, ¡quiero ir a la escuela solo!" Bueno, entonces, encontré el reclamo justo, solicité un período de gracia de dos semanas y comencé los preparativos.
Como tengo algo de experiencia escribiendo aplicaciones, y mi hija constantemente carga en el bolsillo del iPhone SE, como preparación, se decidió escribir rápidamente una aplicación que mostrara dónde está la hija en este momento en particular. Sí, sé que ahora hay muchas aplicaciones de este tipo (incluso una funcionalidad similar apareció recientemente en Google Maps), y era posible utilizar alguna solución preparada, pero estaba interesado en escribir algo propio.
¿Por qué VKontakte?
Como no quisiera asociarme con el procesamiento y almacenamiento de los datos personales de otras personas (en una posible perspectiva) en mi equipo con todos los "encantos" que surgen de esto, pensé en cómo prescindir de mi propio servidor. Y luego me di cuenta: después de todo, ¡hay un monstruo como VKontakte! Está de moda, es poderoso y tiene su propia API desarrollada, y lo más importante, todos nuestros niños han estado sentados en él durante mucho tiempo y han estado apretados (no puedo decir que me haya gustado, pero es una realidad). Pero demonios, Holmes, ¿cómo puedo ingresar los datos de ubicación para que, en primer lugar, no aparezca donde no es necesario, y en segundo lugar, para que pueda controlar el acceso a estos datos para que los pedobirs malos puedan no llegaste allí?
Las notas vinieron al rescate. Sí, esas mismas notas de Wikipedia que una vez (según los rumores) eran muy populares y ahora están en el corral, en su mayor parte dejaron de parpadear en las cintas y se trasladaron a una sección separada del sitio, a la que no llegarás en una cabra cojo. Puede colocar datos de texto arbitrarios en ellos, pero lo principal es que se les pueden asignar listas de acceso que enumeran personas y grupos que pueden ver y comentar esta nota.
El esquema general de la aplicación en mis ojos comenzó a verse así:
- Cree una lista de amigos con los que desee compartir datos de ubicación (lo llamé "Amigos de confianza");
- Creamos una nota con un nombre específico, otorgamos derechos para verla en la lista anterior, anotamos los datos de ubicación allí y los actualizamos periódicamente;
- Regularmente revisamos la lista de amigos de confianza, verificamos si también tienen una nota con este nombre específico, si es así, intentamos extraer datos sobre la ubicación del amigo de su contenido, y si tiene éxito, lo mostramos en el mapa;
- ???
- BENEFICIOS!
Entonces, hay una idea, depende de lo pequeño darse cuenta.
iOS
Como su hija usa el iPhone, era lógico comenzar la implementación con la versión de iOS. Con miras a la plataforma cruzada, Qt fue elegido como marco, porque he estado familiarizado con él durante mucho tiempo, y el buen viejo Open Street Map, para el que hay un complemento en Qt Location, fue elegido como el motor del mapa. Dado que la aplicación se creó originalmente como código abierto, las restricciones de licencia de Qt no me asustaron.
La GUI fue escrita en QML, para trabajar con VK, me conecté y usé el
SDK VK iOS normal, está escrito en Objective-C, por lo que su integración no causó ningún problema. El trabajo en segundo plano en iOS se implementa a través del servicio de cambio de ubicación significativo. Para reducir el consumo de energía, la aplicación monitorea la actividad de los movimientos, y si comprende que una persona se sienta durante aproximadamente un lugar durante mucho tiempo (por ejemplo, vino a la escuela o la oficina), entonces reduce la precisión requerida para determinar la geolocalización, lo que obliga al sistema operativo a cambiar a formas menos intensivas de energía para determinarlo (cómo como regla, en torres celulares). Si la aplicación comprende que la persona ha comenzado a moverse activamente, la precisión aumenta nuevamente.
El código fuente completo para la versión de iOS está disponible en
GitHub . Aquí hay un par de puntos no obvios que encontré en el proceso de implementación:
Anulación de métodos NSApplicationDelegate en una aplicación QtEl SDK de iOS de VKontakte requiere agregar llamadas a algunas de sus funciones en la aplicación: didFinishLaunchingWithOptions: y application: openURL: options: method. Antes de alguna versión de Qt (en mi opinión, antes de 5.11), era suficiente crear una categoría para QIOSApplicationDelegate de esta manera:
@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate> @end @interface QIOSApplicationDelegate (QIOSApplicationDelegateVKGeoCategory) @end @implementation QIOSApplicationDelegate (QIOSApplicationDelegateVKGeoCategory) - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [...] } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { [...] } @end
Pero en las versiones recientes de Qt, QIOSApplicationDelegate ya tiene una implementación de la aplicación: openURL: options: por lo que la opción con categorías ya no funciona. Tuve que hacer un heredero de QIOSApplicationDelegate y asignar un delegado a través de setDelegate:
@interface VKGeoApplicationDelegate : QIOSApplicationDelegate @end @implementation VKGeoApplicationDelegate - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options { [...] } @end void InitializeVKGeoApplicationDelegate() { [[UIApplication sharedApplication] setDelegate:[[VKGeoApplicationDelegate alloc] init]]; } int main(int argc, char *argv[]) { [...] InitializeVKGeoApplicationDelegate(); [...] }
Error al manejar desde VKRequestFrente a que VKRequest por error devolvió un NSError vacío (vacío). Hice un parche que parchea el parche anterior de alguien y
solicita la extracción de este parche, pero aún se cuelga en los no revisados.
Android
La siguiente fue la versión para Android. El código GUI se reutilizó desde iOS casi por completo, para interactuar con el VK, nuevamente se usó el
SDK VK de Android normal, cuya interacción ocurre a través del JNI, el trabajo en segundo plano se implementa de acuerdo con los convenios de Google para tales aplicaciones, es decir, a través del Servicio en primer plano. Por supuesto, también se implementa la lógica para reducir el consumo de energía, similar a la utilizada en iOS.
El conjunto completo de código fuente para la versión de Android está disponible nuevamente en
GitHub , y aquí hay un par de puntos no obvios que encontré en el proceso de implementación de esta versión:
Cómo crear un servicio de Android en QtPara crear un servicio en Qt 5.10, apareció la clase QAndroidService, que debería usarse en lugar de QGuiApplication. Puede compilar .so por separado para actividad y servicio, o puede usar uno .so para todo, y para que el código entienda en qué modo funciona, puede especificar este modo a través de la tecla de línea de comando, algo como esto:
<service android:name=".VKGeoService"> <meta-data android:name="android.app.arguments" android:value="-service"/> </service>
int main(int argc, char *argv[]) { if (argc == 1) { QGuiApplication app(argc, argv); [...] } else if (argc == 2 && QString(argv[1]) == "-service") { QAndroidService app(argc, argv); [...] } else { return 0; } }
Extraña actividad "colgando" en onDestroy ()En el proceso de implementación del servicio, se hizo evidente un problema extraño: QtActivity "colgó" en algún lugar de las entrañas de su onDestroy (), sujeto a la disponibilidad de un servicio en primer plano en funcionamiento. Aparentemente, Qt no espera que después de que se complete la actividad, algo más pueda quedar de la aplicación. El problema se resolvió espaciando la actividad y el servicio en diferentes procesos mediante el uso de android: process en el manifiesto:
<service android:name=".VKGeoService" android:process=":VKGeoService"> [...] </service>
y superando el proceso en el que se ejecuta la actividad en un onDestroy () anulado:
@Override public void onDestroy() { [...] Process.killProcess(Process.myPid()); }
Sí, la pelusa jura constantemente por esto, pero aún no me resulta obvio cómo tratarlo de manera diferente, pero poner en práctica QTBUG con PoC sobre este tema aún no llega a nada.
ACTUALIZACIÓN : en Qt 5.12.3 (quizás un poco antes, no verifiqué) el error al colgar QtActivity.onDestroy () se corrigió cuando se inició el servicio, esta solución ya no es necesaria.
Falta la llamada de errorBlock al cancelar VKBatchRequestUtilizo ampliamente las solicitudes por lotes para facilitar la carga en los servidores VKontakte, y es bajo Android (todo funciona bien en iOS) que encontré un problema si VKBatchRequest se canceló y no se llamaron a errorBlocks para solicitudes canceladas. Solucioné este problema en la versión local de la biblioteca, realicé el parche y la
solicitud de extracción apropiados
para este parche, pero nuevamente se cuelga en los no revisados.
Conclusión
La versión de iOS de Apple se ha colocado fácilmente en la App Store, y todavía está disponible allí. La versión de Android vivió en Google Play durante un tiempo hasta que se endureció la Política de Google Play (estipulaba que las aplicaciones que rastreaban la geolocalización deberían ser explícitas destinado para uso familiar o corporativo), después de lo cual mi aplicación se bloqueó de forma segura allí. Para mi intento de apelar, un empleado responsable de Google (o tal vez era un bot, ahora no es tan obvio quién responde exactamente a sus preguntas) declaró firmemente que "bueno, esta aplicación NO PUEDE SER USADA SOLAMENTE para el seguimiento familiar o corporativo" , a lo que no pude encontrar nada que discutir; de hecho, con un martillo no solo puede martillar las uñas, sino también golpear la cabeza ... Coloqué la versión de Android en Yandex.Store y Amazon Appstore y como APK en el sitio web del proyecto.
Me alegraría si esta aplicación es útil para alguien como una ayuda visual para aclarar algunos momentos no obvios al escribir una aplicación Qt para iOS / Android, especialmente aquellos relacionados con la implementación del servicio Android en Qt (esta funcionalidad es relativamente nueva, ejemplos de implementación, cuánto No sé mucho) También estaré encantado de responder preguntas en los comentarios, si corresponde.