Текст книги "Разработка Android-приложений в деталях"
Автор книги: Тимур Машнин
Жанр: Компьютеры: прочее, Компьютеры
Возрастные ограничения: +12
сообщить о неприемлемом содержимом
Текущая страница: 19 (всего у книги 20 страниц)
});
$ (» <div/>», {
«class»: «list-group»,
html: items.join (»»)
}).appendTo (".col_3»);
$ (".btn-map» ).click (function () {
var route = $(this).attr (’data-route’).split (»,»);
var title = $(this).attr (’data-title’);
for (var i = 0; i <route. length; i++) {
var latLng =new google.maps.LatLng(route[i+1].replace («lat:»,»»), route[i].replace («lng:»,»»));
var marker = new google.maps.Marker ({
position: latLng,
title: title,
map: map
});
map.setCenter (latLng);
i=i+1;
}
});
$ (".btn-mapTrack» ).click (function () {
var route = $(this).attr (’data-route’).split (»,»);
var title = $(this).attr (’data-title’).split (»,»);
var j=0;
for (var i = 0; i <route. length; i++) {
var latLng =new google.maps.LatLng (route [i], route [i+1]);
var marker = new google.maps.Marker ({
position: latLng,
title: title [j],
map: map
});
map.setCenter (latLng);
i=i+1;
j=j+1;
}
});
$ (".btn-state» ).click (function () {
var name = $(this).attr (’data-name’);
var url = 'http://buisness-control.appspot.com/puttaskstate/?callback=?';
$.ajax ({
type: «GET»,
url: url,
data: {
state:’old’,
name: name
},
async: false,
jsonpCallback: ’putTaskState’,
contentType: ’application/json’,
dataType: ’jsonp’,
success: function (json) {
location.reload ();
}
});
});
$ (".btn-del-task» ).click (function () {
var name = $(this).attr (’data-name’);
var url = 'http://buisness-control.appspot.com/deletetask/?callback=?';
$.ajax ({
type: «GET»,
url: url,
data: {
name: name
},
async: false,
jsonpCallback: ’deleteTask’,
contentType: ’application/json’,
dataType: ’jsonp’,
success: function (json) {
location.reload ();
}
});
});
}
});
</script>
</div>
<div class=«clearfix»> </div>
</div>
<div class=«copy»>
<p> Copyright © 2015 TM SoftStudio </p>
</div>
</div>
</div>
<! – /#page-wrapper – >
</div>
<! – /#wrapper – >
<! – Bootstrap Core JavaScript – >
<script src=«js/bootstrap. min. js»> </script>
</body>
</html>
Страница «Архив Заданий» позволяет просмотреть задания со статусом «old», включая трекинги и отчеты о его выполнении, присланные сотрудниками.
<!DOCTYPE HTML>
<html>
<head>
<title> Business Control </title>
<meta name=«viewport» content=«width=device-width, initial-scale=1»>
<meta http-equiv=«Content-Type» content=«text/html; charset=utf-8» />
<script type=«application/x-javascript»> addEventListener («load», function () {setTimeout (hideURLbar, 0);}, false); function hideURLbar () {window.scrollTo (0,1);} </script>
<! – Bootstrap Core CSS – >
<link href=«css/bootstrap. min. css» rel=’stylesheet’ type=’text/css’ />
<! – Custom CSS – >
<link href=«css/style. css» rel=’stylesheet’ type=’text/css’ />
<link href=«css/font-awesome. css» rel=«stylesheet»>
<! – jQuery – >
<script src=«js/jquery. min. js»> </script>
<! – – webfonts – ->
<link href='//fonts.googleapis.com/css? family=Roboto:400,100,300,500,700,900» rel=’stylesheet’ type=’text/css’>
<! – Nav CSS – >
<link href=«css/custom. css» rel=«stylesheet»>
<! – Metis Menu Plugin JavaScript – >
<script src=«js/metisMenu. min. js»> </script>
<script src=«js/custom. js»> </script>
<! – Calendar – >
<script type=«text/javascript» src=«js/bootstrap-datepicker. js»> </script>
<script type=«text/javascript» src="js/bootstrap-datepicker.ru.js» charset=«UTF-8»> </script>
<link href=«css/datepicker. css» rel=«stylesheet»>
<! – Editor – >
<script src="//cdn.tinymce.com/4/tinymce. min. js»> </script>
<script>tinymce.init ({selector: «#editor’}); </script>
</head>
<body>
<div id=«wrapper»>
<! – Navigation – >
<nav class=«top1 navbar navbar-default navbar-static-top» role=«navigation» style=«margin-bottom: 0»>
<div class=«navbar-header»>
<button type=«button» class=«navbar-toggle» data-toggle=«collapse» data-target=".navbar-collapse»>
<span class=«sr-only»> Toggle navigation </span>
<span class=«icon-bar»> </span>
<span class=«icon-bar»> </span>
<span class=«icon-bar»> </span>
</button>
<a class=«navbar-brand» href=«#»> Архив Заданий </a>
</div>
<! – /.navbar-header – >
<div class=«navbar-default sidebar» role=«navigation»>
<div class=«sidebar-nav navbar-collapse»>
<img src="img/logo.png» />
<ul class=«nav» id=«side-menu»>
<li>
<a href="index.html»> <i class=«fa fa-dashboard fa-fw nav_icon»> </i> Dashboard </a>
</li>
<li>
<a href=«#»> <i class=«fa fa-users»> </i> Сотрудники <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="groups-list.html»> Группы </a>
</li>
<li>
<a href="users-list.html»> Общий список </a>
</li>
</ul>
<! – /.nav-second-level – >
</li>
<li>
<a href=«#»> <i class=«fa fa-truck»> </i> Маршрут <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="route.html»> Выбрать маршрут </a>
</li>
<li>
<a href=«#»> Маршруты <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="new-routes.html»> Новые </a>
</li>
<li>
<a href="old-routes.html»> Архив </a>
</li>
</ul>
</li>
</ul>
<! – /.nav-second-level – >
</li>
<li>
<a href=«#»> <i class=«fa fa-file»> </i> Задание <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="task.html»> Создать задание </a>
</li>
<li>
<a href=«#»> Задания <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="new-tasks.html»> Новые </a>
</li>
<li>
<a href="old-tasks.html»> Архив </a>
</li>
</ul>
</li>
</ul>
<! – /.nav-second-level – >
</li>
<li>
<a href=«#»> <i class=«fa fa-file-text»> </i> Текст задания <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="desc.html»> Создать описание </a>
</li>
<li>
<a href=«#»> Описания <span class=«fa arrow»> </span> </a>
<ul class=«nav nav-second-level»>
<li>
<a href="new-descs.html»> Новые </a>
</li>
<li>
<a href="old-descs.html»> Архив </a>
</li>
</ul>
</li>
</ul>
<! – /.nav-second-level – >
</li>
<li>
<a href=«#»> <i class=«fa fa-android»> </i> Мобильные приложения </a>
</li>
</ul>
</div>
<! – /.sidebar-collapse – >
</div>
<! – /.navbar-static-side – >
</nav>
<div id=«page-wrapper»>
<div class=«graphs»>
<div class = «col_3»>
<div class=«clearfix»> </div>
</div>
<div class=«col_1»>
<div class=«col-md-6»>
<div class=«refresh» style=«cursor: pointer; margin-left:22%"> <i class=«fa fa-refresh»> </i> </div>
<div class=«datepicker»> </div>
<script type=«text/javascript»>
var dp = $ (». datepicker’).datepicker ({
language: «ru-RU»
});
$ (".refresh» ).click (function () {
dp. datepicker (’update’);
});
dp. on (’changeDate’, function (ev) {
});
</script>
</div>
<div class=«clearfix»> </div>
</div>
<div class=«span_11»>
<div class=«col-md-12»>
<div id=«map» style=«height:500px;"> </div>
<script>
var map;
function initMap () {
map = new google.maps.Map(document.getElementById (’map’), {
zoom: 15
});
var infoWindow = new google.maps.InfoWindow ({map: map});
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition (function (position) {
var pos = {
lat: position.coords.latitude,
lng: position.coords. longitude
};
infoWindow.setPosition (pos);
map.setCenter (pos);
}, function () {
handleLocationError (true, infoWindow, map.getCenter ());
});
} else {
// Browser doesn’t support Geolocation
handleLocationError (false, infoWindow, map.getCenter ());
}
}
function handleLocationError (browserHasGeolocation, infoWindow, pos) {
infoWindow.setPosition (pos);
infoWindow.setContent (browserHasGeolocation?
«Error: The Geolocation service failed.» :
«Error: Your browser doesn’t support geolocation.»);
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCb9Iir38HyF_E3_hmf3mHHum_tJbgvjXs&callback=initMap"
async defer> </script>
<script>
var url = 'http://buisness-control.appspot.com/tasks/?callback=?';
$.ajax ({
type: «GET»,
url: url,
data: {
state:’old’
},
async: true,
jsonpCallback: ’getNewTasks’,
contentType: «application/json»,
dataType: ’jsonp’,
success: function (json) {
var items = [];
$.each (json. tasks, function (key, val) {
var track=«»;
var trackRoute=«»;
var trackAccount=«»;
if (val.track===undefined) {
track=«»;
trackRoute=«»;
trackAccount=«»;
} else {
$.each (val.track, function (key, subval) {
track=track+"n"+subval.account+" Дата: "+subval. date+" Координаты: "+subval.lat+" "+subval. lng;
if(trackRoute=="")trackRoute=subval.lat+»,»+subval. lng;
trackRoute=trackRoute+","+subval.lat+»,»+subval. lng;
if(trackAccount=="")trackAccount=subval.account;
trackAccount=trackAccount+","+subval.account;
});
}
var subitems= [];
if (val.reports!==undefined) {
$.each (val.reports, function (key, subval) {
var reportAccount=subval.account;
var reportText=subval.report;
var reportPhotos=subval.photos;
var subsubitems= [];
if (reportPhotos!==undefined) {
$.each (reportPhotos, function (key, subsubval) {
var url=subsubval.servingUrl;
var key=subsubval. blobKey;
subsubitems. push (» <br/> <image class=’img-responsive’ src="+url+" alt=«»> <br/>»);
});
}
subitems. push (» <div class=’row’> <div class=’col-sm-12»> <br/> <p class=’label label-success’> Отчет: </p> <p>"+reportAccount+"</p> <p> <textarea class='form-control'>"+reportText+"</textarea></p><p>"+subsubitems.join (»») +"</p> </div> </div>»);
});
}
items. push (» <br/> <a href=«#» class=’list-group-item’ data-toggle=’collapse’ data-target=«#» + val.name.replace (/ [.,:,/,, (,),=,?, -,@] /g,»») + «»>" + val.name + «</a> <div id=„“ + val.name.replace (/ [.,:,/,, (,),=,?, -,@] /g,»») + «» class=’collapse’> <div class=’col-sm-12»>»+val. date+"</div> <div class=’col-sm-12»> <br/> <p class=’label label-success’> Описание: </p> <textarea class='form-control'>"+JSON.stringify(val.descs).replace (/ [" []] /g,»») +"</textarea> </div> <div class=’col-sm-12»> <br/> <p class=’label label-success’> Сотрудники: </p> <textarea class='form-control'>"+JSON.stringify(val.users).replace (/ [" []] /g,»») +"</textarea> </div> <div class=’col-sm-12»> <br/> <p class=’label label-success’> Маршрут: </p> <textarea class='form-control'>"+JSON.stringify(val.routes).replace (/ [" [] {}] /g,»») +"</textarea> </div> <div class=’row’> <div class=’col-sm-4»> <button type=’button’ class=’btn btn-primary btn-map’ data-title=«»+val. date+«» data-route='"+JSON.stringify(val.routes).replace (/ [" [] {}] /g,»») +«»> Показать на карте </button> </div> </div> <br/> <div class=’col-sm-12»> <br/> <p class=’label label-success’> Отслеживание: </p> <textarea class=’form-control’>"+track+"</textarea> </div> <br/> <div class=’row’> <div class=’col-sm-4»> <button type=’button’ class=’btn btn-primary btn-mapTrack’ data-title=«»+trackAccount+«» data-route=«»+trackRoute+«»> Показать на карте</button></div></div><br/>"+subitems.join (»») +"<br/> <div class=’row’> <div class=’col-sm-4»> <button type=’button’ class=’btn btn-primary btn-state’ data-name='"+val.name+«»> Новое задание </button> </div> <div class=’col-sm-4»> <button type=’button’ class=’btn btn-danger btn-del’ data-name='"+val.name+«»> Удалить </button> </div> </div> </div>»);
});
$ (» <div/>», {
«class»: «list-group»,
html: items.join (»»)
}).appendTo (".col_3»);
$ (".btn-mapTrack» ).click (function () {
var route = $(this).attr (’data-route’).split (»,»);
var title = $(this).attr (’data-title’).split (»,»);
var j=0;
for (var i = 0; i <route. length; i++) {
var latLng =new google.maps.LatLng (route [i], route [i+1]);
var marker = new google.maps.Marker ({
position: latLng,
title: title [j],
map: map
});
map.setCenter (latLng);
i=i+1;
j=j+1;
}
});
$ (".btn-map» ).click (function () {
var route = $(this).attr (’data-route’).split (»,»);
var date = $(this).attr (’data-date’);
for (var i = 0; i <route. length; i++) {
var latLng =new google.maps.LatLng(route[i+1].replace («lat:»,»»), route[i].replace («lng:»,»»));
var marker = new google.maps.Marker ({
position: latLng,
title: date,
map: map
});
map.setCenter (latLng);
i=i+1;
}
});
$ (".btn-state» ).click (function () {
var name = $(this).attr (’data-name’);
var url = 'http://buisness-control.appspot.com/puttaskstate/?callback=?';
$.ajax ({
type: «GET»,
url: url,
data: {
state:’new’,
name: name
},
async: false,
jsonpCallback: ’putTaskState’,
contentType: ’application/json’,
dataType: ’jsonp’,
success: function (json) {
location.reload ();
}
});
});
$ (".btn-del» ).click (function () {
var name = $(this).attr (’data-name’);
var url = 'http://buisness-control.appspot.com/deletetask/?callback=?';
$.ajax ({
type: «GET»,
url: url,
data: {
name: name
},
async: false,
jsonpCallback: ’deleteTask’,
contentType: ’application/json’,
dataType: ’jsonp’,
success: function (json) {
location.reload ();
}
});
});
}
});
</script>
</div>
<div class=«clearfix»> </div>
</div>
<div class=«copy»>
<p> Copyright © 2015 TM SoftStudio </p>
</div>
</div>
</div>
<! – /#page-wrapper – >
</div>
<! – /#wrapper – >
<! – Bootstrap Core JavaScript – >
<script src=«js/bootstrap. min. js»> </script>
</body>
</html>
Использование Material Design в Eclipse
При создании Android проектов, работающих с Material Design, в среде Eclipse, в проект необходимо добавить библиотеки andoid design support и recyclerview.
Для добавления библиотеки andoid design support в среде Eclipse импортируем с сохранением папку android-sdksextrasandroidsupportdesign.
В свойствах библиотеки в разделе Android в Project Build Target отметим последнюю версию API и добавим зависимость от библиотеки appcompat_v7.
Для добавления библиотеки recyclerview в среде Eclipse импортируем с сохранением папку android-sdksextrasandroidsupportv7recyclerview.
В свойствах библиотеки в разделе Android в Project Build Target отметим последнюю версию API и добавим зависимость от библиотеки appcompat_v7.
Создадим проект Android приложения на основе шаблона Blank Activity.
В свойствах проекта в разделе Android в Project Build Target добавим зависимость от библиотек appcompat_v7, andoid design support и recyclerview.
В Android Studio создадим проект на основе шаблона Navigation Drawer Activity.
Скопируем содержимое папок appsrcmain Android Studio проекта в Eclipse проект.
Push уведомления
Android + Google Cloud Messaging (GCM)
В консоли Google Cloud Platform создадим проект.
Включим Google Cloud Messaging API для этого проекта.
Создадим server API key для Google Cloud Messaging.
В среде Eclipse создадим проект Android приложения, в который добавим библиотеку Google Play Services https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project.
В файл манифеста добавим разрешения.
<uses-permission android:name="android.permission.INTERNET» />
<uses-permission android:name="android.permission. WAKE_LOCK» />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE» />
<permission android:name="com.tmsoftstudio.breakingnews. C2D_MESSAGE»
android: protectionLevel=«signature» />
<uses-permission android:name="com.tmsoftstudio.breakingnews. C2D_MESSAGE» />
Для регистрации Android приложения в сервисе GCM в класс активности добавим код:
private String regid;
private String PROJECT_NUMBER = «1222…»;
private SharedPreferences mSettings;
private Context context;
final int REQUEST_CODE = 0;
public final static int RESULT_CODE = 1;
public final static String PARAM_PINTENT = «PendingIntent»;
public final static String PARAM_RESULT = «Result»;
@Override
protected void onCreate (Bundle savedInstanceState) {
super. onCreate (savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar (toolbar);
context = this;
mSettings = getSharedPreferences («APP_PREFERENCES», Context.MODE_PRIVATE);
if (!mSettings.contains («SENDER_ID»)) {
SharedPreferences. Editor editor = mSettings. edit ();
editor. putString («SENDER_ID», PROJECT_NUMBER);
editor.commit ();
}
if (!mSettings.contains («REG_ID»)) {
PendingIntent pi;
pi = createPendingResult (REQUEST_CODE, new Intent (), 0);
Intent intent = new Intent (context, InstanceIDIntentService.class);
intent. putExtra (PARAM_PINTENT, pi);
startService (intent);
}
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener (new View. OnClickListener () {
@Override
public void onClick (View view) {
Snackbar.make (view, «Replace with your own action», Snackbar. LENGTH_LONG)
.setAction («Action», null).show ();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle (
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener (toggle);
toggle.syncState ();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener (this);
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_CODE) {
regid=data.getStringExtra(MainActivity.PARAM_RESULT);
View view = (View) findViewById(R.id.content);
Snackbar.make (view, regid, Snackbar.LENGTH_LONG).setAction («Action», null).show ();
SharedPreferences. Editor editor = mSettings. edit ();
editor. putString («REG_ID», regid);
editor.commit ();
}
}
}
Здесь PROJECT_NUMBER это номер созданного проекта в Google Cloud Platform.
Объект PendingIntent создается методом createPendingResult активности для получения уникального регистрационного токена из сервиса регистрации для его сохранения в методе обратного вызова onActivityResult активности.
Создадим сервис регистрации.
<service android:name=".InstanceIDIntentService» android: exported=«false»/>
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net. URL;
import com.google.android.gms. gcm. GoogleCloudMessaging;
import com.google.android.gms.iid.InstanceID;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net. Uri;
import android. os. Handler;
import android. os. Looper;
import android.widget.Toast;
public class InstanceIDIntentService extends IntentService {
// abbreviated tag name
private static final String TAG = «InstanceIDIntentService»;
private SharedPreferences mSettings;
public InstanceIDIntentService () {
super (TAG);
}
@Override
protected void onHandleIntent (Intent intent) {
InstanceID instanceID = InstanceID.getInstance (this);
mSettings = getSharedPreferences («APP_PREFERENCES», Context.MODE_PRIVATE);
String senderId = mSettings.getString («SENDER_ID», «»);
try {
String token = instanceID.getToken (senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE);
int code=sendRegistrationToServer (token);
if (code==200) {
PendingIntent pi = intent.getParcelableExtra(MainActivity.PARAM_PINTENT);
Intent intentResult = new Intent().putExtra(MainActivity.PARAM_RESULT, token);
pi.send(InstanceIDIntentService.this,MainActivity.RESULT_CODE, intentResult);
} else {
Handler handler = new Handler(Looper.getMainLooper ());
handler.post (new Runnable () {
@Override
public void run () {Toast.makeText(InstanceIDIntentService.this.getApplicationContext (),«Registration failed!",Toast.LENGTH_SHORT).show ();
}
});
}
} catch (Exception e) {
e.printStackTrace ();
}
}
private int sendRegistrationToServer (String token) {
URL url;
HttpURLConnection conn=null;
int code=0;
try {
url = new URL (»http://backend.appspot.com/backend");
conn = (HttpURLConnection) url. openConnection ();
conn.setReadTimeout (10000);
conn.setConnectTimeout (15000);
conn.setRequestMethod («POST»);
conn.setDoInput (true);
conn.setDoOutput (true);
Uri. Builder builder = new Uri. Builder ()
.appendQueryParameter («token», token);
String query = builder.build().getEncodedQuery ();
OutputStream os = conn.getOutputStream ();
BufferedWriter writer = new BufferedWriter (
new OutputStreamWriter (os, «UTF-8»));
writer. write (query);
writer. flush ();
writer.close ();
os.close ();
code=conn.getResponseCode ();
} catch (Exception e) {
e.printStackTrace ();
} finally {
if (conn!= null) {
conn. disconnect ();
}
}
return code;
}
}
Здесь с помощью номера проекта создается запрос к сервису GCM и в ответ получается уникальный регистрационный токен, который затем отсылается на сервер и передается с помощью объекта PendingIntent обратно в активность.
Для создания серверной части в среде Eclipse создадим проект Web Application Project, в файле appengine-web. xml которого укажем идентификатор проекта Google Cloud Platform.
В сервлет GAE приложения добавим код сохранения токена.
import java.io.IOException;
import javax.servlet.http.*;
import com. google. appengine. api. datastore. DatastoreService;
import com. google. appengine. api. datastore. DatastoreServiceFactory;
import com. google. appengine. api. datastore. Entity;
@SuppressWarnings («serial»)
public class BackendServlet extends HttpServlet {
public void doPost (HttpServletRequest req, HttpServletResponse resp) throws IOException {
String token=req.getParameter («token»);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService ();
Entity tokenEntity = new Entity («Token»);
tokenEntity.setProperty («token», token);
datastore. put (tokenEntity);
}
}
Так как токен периодически обновляется сервисом GCM, нужно создать слушатель, который будет автоматически запускаться при обновлении токена сервисом GCM и обновлять его для Android приложения и для серверной части.
<service
android:name=".RefreshInstanceIDListenerService»
android: exported=«false»>
<intent-filter>
<action android:name="com.google.android.gms.iid.InstanceID»/>
</intent-filter>
</service>
import com.google.android.gms.iid.InstanceIDListenerService;
import android.content.Intent;
public class RefreshInstanceIDListenerService extends InstanceIDListenerService {
@Override
public void onTokenRefresh () {
// Fetch updated Instance ID token and notify of changes
Intent intent = new Intent (this, InstanceIDIntentService.class);
startService (intent);
}
}
Для отправки сообщения от сервера Android приложению, в папку lib и в Build Path проекта GAE приложения добавим библиотеки json-simple-1.1.jar (http://grepcode.com/snapshot/repo1.maven.org/maven2/com.googlecode.json-simple/json-simple/1.1) и gcm-server. jar (https://github.com/slorber/gcm-server-repository/tree/master/deployer).
В код сервлета добавим:
import java.io.IOException;
import javax.servlet.http.*;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Sender;
import com.google.android.gcm.server.Result;
import com. google. appengine. api. datastore. DatastoreService;
import com. google. appengine. api. datastore. DatastoreServiceFactory;
import com. google. appengine. api. datastore. Entity;
@SuppressWarnings («serial»)
public class BackendServlet extends HttpServlet {
private String SERVER_KEY=«AIza…»;
public void doPost (HttpServletRequest req, HttpServletResponse resp) throws IOException {
String token=req.getParameter («token»);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService ();
Entity tokenEntity = new Entity («Token»);
tokenEntity.setProperty («token», token);
datastore. put (tokenEntity);
Sender sender = new Sender (SERVER_KEY);
Message message = new Message. Builder ()
.addData («sender», «Project Name»)
.addData («message», «this is the message»)
.build ();
Result result = sender.send (message, token, 1);
}
}
Здесь SERVER_KEY это созданный server API key для Google Cloud Messaging.
Для получения сообщения Android приложением, в файл манифеста добавим объявление сервиса, который будет обрабатывать GCM сообщение.
<receiver
android:name="com.google.android.gms. gcm. GcmReceiver»
android: exported=«true»
android:permission="com.google.android.c2dm.permission.SEND»>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE» />
<category android:name="com.tmsoftstudio.breakingnews» />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION»/>
<category android:name="com.tmsoftstudio.breakingnews»/>
</intent-filter>
</receiver>
А также создадим сервис обработки входящего сообщения.
<service
android: name=». GcmMessageHandler»
android: exported=«false»>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE» />
</intent-filter>
</service>
import com.google.android.gms. gcm. GcmListenerService;
import android.app.NotificationManager;
import android.content.Context;
import android. os. Bundle;
import android.support.v4.app.NotificationCompat;
public class GcmMessageHandler extends GcmListenerService {
public static final int MESSAGE_NOTIFICATION_ID = 123123;
@Override
public void onMessageReceived (String from, Bundle data) {
String title = data.getString («sender»);
String message = data.getString («message»);
Context context = getBaseContext ();
NotificationCompat. Builder mBuilder = new NotificationCompat. Builder (context) .setSmallIcon(R.drawable.ic_launcher).setContentTitle (title)
.setContentText (message);
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify (MESSAGE_NOTIFICATION_ID, mBuilder. build ());
}
}
Для рассылки topic сообщений в проекте GAE приложения заменим библиотеку gcm-server. jar (https://github.com/slorber/gcm-server-repository/tree/master/deployer) на библиотеку https://github.com/google/gcm.
Это позволит заменить строку sender.send (message, token, 1); на sender.send (message, "/topics/news», 1);
Для подписки Android приложения на topic сообщения в сервисе InstanceIDIntentService в методе onHandleIntent добавим код:
String token = instanceID.getToken (senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE);
GcmPubSub pubSub = GcmPubSub.getInstance (this);
pubSub.subscribe (token, "/topics/news», null);
Изменим сервис GcmMessageHandler.
import com.google.android.gms. gcm. GcmListenerService;
import android.app.NotificationManager;
import android.content.Context;
import android. os. Bundle;
import android.support.v4.app.NotificationCompat;
public class GcmMessageHandler extends GcmListenerService {
public static final int MESSAGE_NOTIFICATION_ID = 123123;
@Override
public void onMessageReceived (String from, Bundle data) {
String title = data.getString («sender»);
String message = data.getString («message»);
if (from.startsWith (»/topics/news»)) {
Context context = getBaseContext ();
NotificationCompat. Builder mBuilder = new NotificationCompat. Builder (context)
.setSmallIcon(R.drawable.ic_launcher).setContentTitle (title+«Topic: News»)
.setContentText (message);
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify (MESSAGE_NOTIFICATION_ID, mBuilder. build ());
} else {
Context context = getBaseContext ();
NotificationCompat. Builder mBuilder = new NotificationCompat. Builder (context)
.setSmallIcon(R.drawable.ic_launcher).setContentTitle (title)
.setContentText (message);
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify (MESSAGE_NOTIFICATION_ID, mBuilder. build ());
}
}
}
Правообладателям!
Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.