I'm trying to implement the functionality of add subscription to youtube channel from android app.
i already done with :
register app on developer console. -Done
package name and SHA-1 certificate fingerprint. -Done
Image
Google account account authentication with "https://www.googleapis.com/auth/youtube" . -Done
Note : functionality is working fine in debug mode.
Issue: when i create a signed apk for publishing app on play store then subscribe button not working throw different errors each time .
i.e With unrestricted api key :
W/System.err: {
"c" : 0,
"errors" : [ {
"domain" : "global",
"reason" : "required",
"message" : "Required parameter: part",
"locationType" : "parameter",
"location" : "part"
} ],
"code" : 400,
"message" : "Required parameter: part"
}
Here is the code that Im doing
// Initialize credentials and service object.
mCredential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(SCOPES)).setBackOff(new ExponentialBackOff());
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
YouTube mService = new YouTube.Builder(transport, jsonFactory, mCredential)
.setApplicationName(getResources().getString(R.string.app_name))
.setYouTubeRequestInitializer(new YouTubeRequestInitializer(Config.KEY))
.build();
channelId = myListModel.getYoutubeChannelId();
// Create a resourceId that identifies the channel ID.
ResourceId resourceId = new ResourceId();
resourceId.setChannelId(channelId);
resourceId.setKind("youtube#channel");
// Create a snippet that contains the resourceId.
SubscriptionSnippet snippet = new SubscriptionSnippet();
snippet.setResourceId(resourceId);
// Create a request to add the subscription and send the request.
// The request identifies subscription metadata to insert as well
// as information that the API server should return in its response.
Subscription subscription = new Subscription();
subscription.setSnippet(snippet);
YouTube.Subscriptions.Insert subscriptionInsert = mService.subscriptions().insert("snippet,contentDetails", subscription);
try {
Subscription returnedSubscription = subscriptionInsert.execute();
// Print information from the API response.
System.out.println("\n================== Returned Subscription ==================\n");
System.out.println(" - Id: " + returnedSubscription.getId());
System.out.println(" - Title: " + returnedSubscription.getSnippet().getTitle());
addSubscriber(myListModel);
} catch (UserRecoverableAuthIOException mLastError) {
startActivityForResult(mLastError.getIntent(), REQUEST_AUTHORIZATION);
}
} catch (GoogleJsonResponseException e) {
System.err.println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : "
+ e.getDetails().getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
e.printStackTrace();
} catch (Throwable t) {
System.err.println("Throwable: " + t.getMessage());
t.printStackTrace();
}
Related
I have the the authenticated user with federated ID. But when I try to access the AWS IOT stuff I get this error which is driving me crazy.
I am following the iot sample code. All the relevant credentials are correct too.
`MQTTHelper`
....
credentialsProvider = new CognitoCachingCredentialsProvider(
mContext.getApplicationContext(), // context
BuildConfig.COGNITO_POOL_ID, // Identity Pool ID
MY_REGION // Region
);
Region region = Region.getRegion(MY_REGION);
mqttManager = new AWSIotMqttManager(clientId, BuildConfig.CUSTOMER_SPECIFIC_ENDPOINT);
mqttManager.setKeepAlive(10);
mAwsIotDataClient = new AWSIotDataClient(credentialsProvider);
String iotDataEndpoint = BuildConfig.CUSTOMER_SPECIFIC_ENDPOINT;
mAwsIotDataClient.setEndpoint(iotDataEndpoint);
mAwsIotDataClient.setRegion(region);
// mqttManager.setMqttLastWillAndTestament(lwt);
mIotAndroidClient = new AWSIotClient(credentialsProvider);
mIotAndroidClient.setRegion(region);
keystorePath = mContext.getFilesDir().getPath();
keystoreName = BuildConfig.KEYSTORE_NAME;
keystorePassword = BuildConfig.KEYSTORE_PASSWORD;
certificateId = BuildConfig.CERTIFICATE_ID;
// To load cert/key from keystore on filesystem
try {
if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, keystoreName)) {
if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, keystorePath,
keystoreName, keystorePassword)) {
Log.d(LOG_TAG, "Certificate " + certificateId
+ " found in keystore - using for MQTT.");
// load keystore from file into memory to pass on connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
keystorePath, keystoreName, keystorePassword);
//btnConnect.setEnabled(true);
Log.i(LOG_TAG, "Connected....");
//CONNECTED_TO_DEVICE = true;
} else {
Log.i(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
}
} else {
Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred retrieving cert/key from keystore.", e);
}
if (clientKeyStore == null) {
IS_CERTIFICATE_GENERATED = false;
Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new key and certificate.");
doGenerateNewCertificate();
} else {
IS_CERTIFICATE_GENERATED = true;
doMqttConnect();
}
}
private static void doMqttConnect() {
Log.d(LOG_TAG, "clientId = " + clientId);
try {
mqttManager.connect(clientKeyStore, new AWSIotMqttClientStatusCallback() {
#Override
public void onStatusChanged(final AWSIotMqttClientStatus status,
final Throwable throwable) {
Log.d(LOG_TAG, "Status = " + String.valueOf(status));
if (mqttManagerConnStatus != null) {
//Send Mqtt Manager Status Back
mqttManagerConnStatus.onStatusChanged(status, throwable);
}
}
});
} catch (final Exception e) {
Log.e(LOG_TAG, "Connection error.", e);
}
and similarly as mentioned in the sample code I am calling GetShadow() in another class
GetThingShadowRequest getThingShadowRequest = new GetThingShadowRequest() .withThingName(thingName);
GetThingShadowResult result = mDashboard.mqttHelper.doGetAwsIotDataClient()
.getThingShadow(getThingShadowRequest);
byte[] bytes = new byte[result.getPayload().remaining()];
result.getPayload().get(bytes);
String resultString = new String(bytes);
return new AsyncTaskResult<String>(resultString);
I am able to get the KMS working so there is no problem with the authenticated (federated Id). The only source of information I get on AWS IOT is just this which is not helpful from client perspective.
Is it the issue with the AWS IOT configuration or code issue? I have to subscribe to the Thing Group, is there anything else I need to do to subscribe to the group?
This is the Thing Group ARN that I needs to subscribe to
arn:aws:iot:us-east-1:XXXXXXXXXX:thinggroup/A_GROUP
Stack Trace
getShadowTask
com.amazonaws.AmazonServiceException: null (Service: AWSIotData; Status Code: 403; Error Code: ForbiddenException; Request ID: f78eea4d-9053-4b19-1840-297dd67c2667)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
at com.amazonaws.services.iotdata.AWSIotDataClient.invoke(AWSIotDataClient.java:571)
at com.amazonaws.services.iotdata.AWSIotDataClient.getThingShadow(AWSIotDataClient.java:406)
at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:519)
at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:497)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
06-18 06:00:54.029 7489-7489/com.lyrebird.abc E/com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter.GetShadowTask: getShadowTask
com.amazonaws.AmazonServiceException: null (Service: AWSIotData; Status Code: 403; Error Code: ForbiddenException; Request ID: f78eea4d-9053-4b19-1840-297dd67c2667)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
at com.amazonaws.services.iotdata.AWSIotDataClient.invoke(AWSIotDataClient.java:571)
at com.amazonaws.services.iotdata.AWSIotDataClient.getThingShadow(AWSIotDataClient.java:406)
at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:519)
at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:497)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:*",
"lambda:*"
],
"Resource": [
"*"
]
}
]
}
Here are the few reasons why you might be getting error 403
In Cognito, there are no appropriate permissions for Update/Get Shadow both for authenticated and unauthenticated pool
The ARN of the Cognito Pool id as well as the IoT are incorrect
Check the IAM policy and the following policy to the Cognito users, Also for the Cognito user, you have to attach AttachPrincipalPolicy policy to give them appropriate permissions for Get/update the shadow. The policy below should be in the Cognito Auth and UnAuth roles.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:AttachPrincipalPolicy"
],
"Resource": [
"*"
]
}
] }
I'm trying to find out why some of our users are getting the error "Required parameter: part" when trying to upload a video into YouTube using YouTube API v3. Below you can see the code that we use for uploading videos. The method params are valid strings that aren't short or too long.
int shareYoutube(#NonNull Uri mediaUri, String mime, String mediaTitle, String postMessage, String accountName)
{
int error = ERR_NO_ERROR;
try {
// Developer tags not supported yet
//https://code.google.com/p/gdata-issues/issues/detail?id=5012
// Authorize the request.
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(getApplicationContext(), Arrays.asList(YouTubeScopes.YOUTUBE_UPLOAD));
credential.setSelectedAccountName(accountName);
// This object is used to make YouTube Data API requests.
YouTube.Builder builder = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential);
builder.setApplicationName("TEST APP");
YouTube youtube = builder.build();
// Add extra information to the video before uploading.
Video video = new Video();
// set privacy
VideoStatus status = new VideoStatus();
status.setPrivacyStatus("public");
video.setStatus(status);
// Most of the video's metadata is set on the VideoSnippet object.
VideoSnippet snippet = new VideoSnippet();
snippet.setTitle(mediaTitle);
snippet.setDescription(postMessage);
// Film & Animation https://gist.github.com/dgp/1b24bf2961521bd75d6c
snippet.setCategoryId("1");
// Set the keyword tags that you want to associate with the video.
List<String> tags = new ArrayList<>();
tags.add("animation");
tags.add("cartoon");
tags.add("2d animation");
tags.add("drawing");
snippet.setTags(tags);
// Add the completed snippet object to the video resource.
video.setSnippet(snippet);
String fileFormat = "video/*";
InputStreamContent mediaContent = new InputStreamContent(fileFormat, getContentResolver().openInputStream(mediaUri));
// Insert the video. The command sends three arguments. The first
// specifies which information the API request is setting and which
// information the API response should return. The second argument
// is the video resource that contains metadata about the new video.
// The third argument is the actual video content.
YouTube.Videos.Insert videoInsert = youtube.videos().insert("snippet,statistics,status", video, mediaContent);
// Insert to a channel
//videoInsert.setOnBehalfOfContentOwnerChannel();
// Set the upload type and add an event listener.
MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
// Indicate whether direct media upload is enabled. A value of
// "True" indicates that direct media upload is enabled and that
// the entire media content will be uploaded in a single request.
// A value of "False," which is the default, indicates that the
// request will use the resumable media upload protocol, which
// supports the ability to resume an upload operation after a
// network interruption or other transmission failure, saving
// time and bandwidth in the event of network failures.
uploader.setDirectUploadEnabled(false);
YouTubeCallbackListener callback = new YouTubeCallbackListener();
uploader.setProgressListener(callback);
// Call the API and upload the video.
Video returnedVideo = videoInsert.execute();
synchronized (callback) {
if (!callback.hasCallbackResult()) {
try {
callback.wait();
error = callback.error;
} catch (InterruptedException e) {
e.printStackTrace();
error = ERR_POST_CANCELED;
}
} else {
error = callback.error;
}
}
if (ERR_NO_ERROR == error && null != returnedVideo)
{
Intent notificationIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://www.youtube.com/watch?v="+returnedVideo.getId()));
mPendingIntent = PendingIntent.getActivity(getBaseContext(), 0, notificationIntent, 0);
}
}
catch (UserRecoverableAuthIOException userRecoverableException)
{
error = ERR_UNABLE_TO_AUTH_ACCOUNT;
try {
GoogleAuthUtil.getTokenWithNotification(
getApplicationContext(), accountName, "oauth2:" + YouTubeScopes.YOUTUBE_UPLOAD, null);
} catch (IOException e) {
} catch (GoogleAuthException e) {
}
} catch (GoogleJsonResponseException e) {
error = ERR_POST_ERROR;
Crashlytics.logException(e);
} catch (IOException e) {
error = ERR_POST_ERROR;
Crashlytics.logException(e);
} catch (Throwable t) {
error = ERR_POST_ERROR;
Crashlytics.logException(t);
}
return error;
}
Error:
400 Bad Request { "errors" : [ { "domain" : "global", "reason" : "required", "message" : "Required parameter: part", "locationType" : "parameter", "location" : "part" } ], "code" : 400, "message" : "Required parameter: part" }
Any thoughts on what could be happening here?
The problem was our proguard script. All we had to do was include the following line to it.
-keep class com.google.api.** { *; }
I'm trying to access the YouTube Data API v3 from within my app to fetch some videos from a specific channnel. I created an API Key and inserted my package name and the SHA-1 fingerprint. However, it does not work.
This is the error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "The Android package name and signing-certificate fingerprint, null and null, do not match the app restrictions configured on your API key. Please use the API Console to update your key restrictions.",
"reason" : "ipRefererBlocked",
"extendedHelp" : "https://console.developers.google.com/apis/credentials?project=1097633804344"
} ],
"message" : "The Android package name and signing-certificate fingerprint, null and null, do not match the app restrictions configured on your API key. Please use the API Console to update your key restrictions."
}
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at de.axelrindle.youtubeapitest.YoutubeConnector.fetchVideoIDS(YoutubeConnector.java:59)
at de.axelrindle.youtubeapitest.util.VideoIDFetcher.fetchVideoIDS(VideoIDFetcher.java:62)
at de.axelrindle.youtubeapitest.InitService.onHandleIntent(InitService.java:57)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
And here is the code, which sends the request:
YoutubeConnector.class
public YoutubeConnector(Context context) {
this.context = context;
youTube = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) throws IOException {}
}).setApplicationName("YouTube Data API v3 Test").build();
try {
query = youTube.search().list("id,snippet");
query.setKey(DevKey.YOUTUBE_API);
query.setType("video");
query.setFields("items(id/videoId,snippet/title,snippet/description,snippet/thumbnails/default/url)");
query.setChannelId("UC3ifTl5zKiCAhHIBQYcaTeg");
query.setMaxResults(maxResults);
} catch (IOException e) {
Log.e("YoutubeConnector", "Failed to connect to YouTube: " + e.getMessage());
}
}
public List<String> fetchVideoIDS() {
List<String> ids = new ArrayList<>();
maxResults += 10;
try {
SearchListResponse response = query.execute();
List<SearchResult> results = response.getItems();
for (SearchResult result : results) {
ids.add(result.getId().getVideoId());
}
} catch (IOException e) {
e.printStackTrace();
}
return ids;
}
Any help is MUCH appreciated!
Fixed it by myself.
I was just using the wrong API key.
EDIT:
Maybe I should mention that it worked when I used an browser api key instead of an android api key.
I've been fighting with Google Drive API for Android for more than 50 hours now, and have not come one inch closer. From my understanding, there are 1001 ways to access Google drive (Google Docs API, REST & Google Drive SDK v2). I'm using Google Drive SDK v2. I want want to access Google Drive to upload jpeg files. Platform, Android 2.2+.
What I've tried:
Using the recently released SDK:
http://code.google.com/p/google-api-java-client/wiki/APIs#Drive_API
I've watched the Google I/O sesssion, but the most important part (how to create a Drive object using your Client ID & Client Secret) was left out:
https://developers.google.com/events/io/sessions/gooio2012/705/
I have created multiple keys on https://code.google.com/apis/console. The last one I've created (and tested with) was created using "Create another client ID..." -> "Installed Application" -> "Android". I've used the key in the ~/.android/debug.keystore.
I've also tried to create a key for an "Other" (instead of Android/iOS) installed app, but this gives me a Client ID and Client secret. It seems like the Drive object does not accept a client secret.
Where the code says "1234567890-abcdefghij123klmnop.apps.googleusercontent.com", I've tried to use both "API key" and the "Client ID", both gave the same error.
My code:
Account account = AccountManager.get(context).getAccountsByType(
"com.google")[0];
String token;
try {
token = GoogleAuthUtil.getToken(context, account.name, "oauth2:"
+ DriveScopes.DRIVE_FILE);
} catch (UserRecoverableAuthException e) {
context.startActivityForResult(e.getIntent(), ASK_PERMISSION);
return;
} catch (IOException e) {
return;
} catch (GoogleAuthException e) {
return;
}
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
Drive.Builder b = new Drive.Builder(httpTransport, jsonFactory, null);
final String tokenCopy = token;
b.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
public void initialize(JsonHttpRequest request) throws IOException {
DriveRequest driveRequest = (DriveRequest) request;
driveRequest.setPrettyPrint(true);
driveRequest
.setKey("1234567890-abcdefghij123klmnop.apps.googleusercontent.com");
driveRequest.setOauthToken(tokenCopy);
}
});
final Drive drive = b.build();
FileList files;
try {
files = drive.files().list().setQ("mimeType=text/plain").execute();
} catch (IOException e) {
e.printStackTrace(); // throws HTTP 400
}
The error I'm getting is:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"location" : "q",
"locationType" : "parameter",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
As the error message suggests, your error is in the query parameter q. The correct syntax for your q parameter is
files = drive.files().list().setQ("mimeType='text/plain'").execute();
and not :
files = drive.files().list().setQ("mimeType=text/plain").execute();
Looking at your code, you are fully authenticated and your request is failing because of this syntax error.
Well, I tried using Account Manager and I am getting "401 Token Invalid" error. What can be the reason.
Debug Log
Account name = xxxxxx#gmail.com
Token is : DQAAALIAAAAh-xxxxxxx
Starting Google DATA API loader-----------------
Inside Google Notebook loader-----------------
Setting Token : DQAAALIAAAAh-xxxxx
Url is : https://docs.google.com/feeds/default/private/full
Exception getting docs feed : 401 Token invalid
Done Google DATA API loader-----------------
Sample Code:
Log.d("Main","\tInside GoogleDATA API -----------------");
HttpTransport transport = new NetHttpTransport();
GoogleHeaders headers = new GoogleHeaders();
Log.d("Main","\tSetting Token : " + authToken);
headers.setGoogleLogin(authToken);
headers.gdataVersion="3.0";
transport.defaultHeaders = headers;
AtomParser parser = new AtomParser();
parser.namespaceDictionary = Namespace.DICTIONARY;
transport.addParser(parser);
try {
DocsUrl url = DocsUrl.forDefaultPrivateFull();
DocumentListFeed feed = DocumentListFeed.executeGet(transport,url);
List<DocumentListEntry> docs = feed.docs;
Log.d("Main","\tDocs count = " + docs.size());
for (Iterator iterator = docs.iterator(); iterator.hasNext();) {
DocumentListEntry documentListEntry = (DocumentListEntry) iterator
.next();
Log.d("Main","\t\tDocument title is : " + documentListEntry.title);
}
} catch (IOException e) {
Log.d("Main","Exception getting docs feed : " + e.getMessage());
//handleException(e);
}
Log.d("Main","\tDone GoogleDATA API -----------------");
you should see how it works on this website http://n01se.net/gmapez/start.html