I have started working on Spring Security. I am doing a HelloWorld application from this link.
My question is, why do we need the #Import annotation?
While working on Spring MVC, I used to define a similar configuration file, but since it was in the same package, I did not need to import it. Why am I importing the SecurityConfig.java file here, then?
The place where I have used the #Import annotation is here
AppConfig.java:
package com.mkyong.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#EnableWebMvc
#Configuration
#ComponentScan({ "com.mkyong.web.*" })
#Import({ SecurityConfig.class })
public class AppConfig {
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
You need to import the security into the main app config class because it won't be picked up by the #ComponentScan because the class is not within the package for scanning #ComponentScan({ "com.mkyong.web.*" }). The security config is not defined in there. You register your main class like:
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
If you don't import the security class into it then the security won't be registered in the application.
Related
I am creating some classes and I am getting this issue: Static members from supertypes must be qualified by the name of the defining type.
post(Documnet document) ->Future
My clases are these:
UserApi
import '../api-helper.dart';
import '../../graphql/documents/login.dart';
import 'dart:async';
class UserAPI extends APIHelper {
static Future<dynamic> login(account) async {
return await post(new Login('name', 'email', 'token', 'refreshToken', 'createdAt', 'expiresAt', false));
}
}
APIHelper
import 'package:graphql_flutter/graphql_flutter.dart' show Client, InMemoryCache;
import '../graphql/document.dart';
import '../graphql/graphql-helper.dart';
import 'dart:async';
class APIHelper {
static const GRAPHQL_URL = 'https://heat-map-api.herokuapp.com/graphql';
static final _client = Client(
endPoint: GRAPHQL_URL,
cache: new InMemoryCache(),
);
static Future<dynamic> post(Document document) async {
return await _client.query(query: GraphQLHelper.getBodyMutation(document), variables: GraphQLHelper.getVariables(document));
}
}
What should I do in order to fix this? I don't have compiled the project yet, but it scares me.
Static members can only be used (outside of their class) by prefixing with the class name.
A better design for helper like that is to use top-level members. See AVOID defining a class that contains only static members rule from the Effective Dart
.
I want to use swagger client generator and feed the json generated by "../v2/api-docs" from the jHipster application. The problem is that without the security definitions the generated code will not work. The JWT token is not added to the API requests, the code is generated without authentication. The http://petstore.swagger.io/v2/swagger.json example has security and securityDefinitions. Where to modify/configure the jhipster application so that the security and security definitions are generated in the json file? {I manually added the security and security definitions to the json file and after that the generated code works and JWT is enabled in the jHipster application, but I don't want to edit the file each time the API changes... } The "securityDefinitions" and "security":[{"petstore_auth":["write:pets","read:pets"]}] sections are completely missing from the generated json file from the jHipster application, even if JWT is enabled and needed to make API requests.
Update 28-09-2020:
Since the update to SpringFox 3, classes are now called
SpringfoxCustomizer
JHipsteSpringfoxCustomizer
Better late than never.
JHipster applications depend on the JHipster Framework, which is in charge of the springfox's Docket configuration.
JHipster Framework's SwaggerAutoConfiguration customizes the springfox Docket with every SwaggerCustomizer bean registered in the application. JHipster registers it's own swagger customizer for the default docket configuration.
This said, you need to add your own docket customizer ir order to include the desired security definitions and any other additional configuration to the springfox's docket. In order to do this you need to:
Create the swagger pacakage inside the already existing config package. Inside it, create a CustomSwaggerConfig class:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class CustomSwaggerConfig {
public CustomSwaggerConfig() {
}
#Bean
public ApplicationSwaggerCustomizer applicationSwaggerCustomizer() {
return new ApplicationSwaggerCustomizer();
}
}
And create the ApplicationSwaggerCustomizer class:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.github.jhipster.config.apidoc.customizer.SwaggerCustomizer;
import springfox.documentation.spring.web.plugins.Docket;
public class ApplicationSwaggerCustomizer implements SwaggerCustomizer {
private final Logger log = LoggerFactory.getLogger(ApplicationSwaggerCustomizer.class);
public ApplicationSwaggerCustomizer() {
}
#Override
public void customize(Docket docket) {
log.debug("Customizing springfox docket...");
// TODO Here you can add all the configurations to the docket
}
}
Now you can add any additional docket configuration.
You can clone default implementation with:
package <YOUR_PACKAGE>;
import static io.github.jhipster.config.JHipsterConstants.SPRING_PROFILE_SWAGGER;
import static springfox.documentation.builders.PathSelectors.regex;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import io.github.jhipster.config.JHipsterProperties;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiKeyVehicle;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Springfox Swagger configuration.
* <p>
* Warning! When having a lot of REST endpoints, Springfox can become a performance issue.
* In that case, you can use the "no-swagger" Spring profile, so that this bean is ignored.
*/
#Configuration
#Profile(SPRING_PROFILE_SWAGGER)
#EnableSwagger2
public class SwaggerConfiguration {
static final String STARTING_MESSAGE = "Starting Swagger with JWT";
static final String STARTED_MESSAGE = "Started Swagger with JWT in {} ms";
static final String MANAGEMENT_TITLE_SUFFIX = "Management API";
static final String MANAGEMENT_GROUP_NAME = "management";
static final String MANAGEMENT_DESCRIPTION = "Management endpoints documentation";
public static final String AUTHORIZATION_HEADER = "Authorization";
private final Logger log = LoggerFactory.getLogger(SwaggerConfiguration.class);
private final JHipsterProperties.Swagger properties;
public SwaggerConfiguration(JHipsterProperties jHipsterProperties) {
this.properties = jHipsterProperties.getSwagger();
}
/**
* Springfox configuration for the API Swagger with JWT docs.
*
* #return the Swagger Springfox configuration
*/
#Bean
public Docket swaggerSpringfoxApiDocket() {
log.debug(STARTING_MESSAGE);
StopWatch watch = new StopWatch();
watch.start();
Docket docket = createDocket();
Contact contact = new Contact(
properties.getContactName(),
properties.getContactUrl(),
properties.getContactEmail()
);
ApiInfo apiInfo = new ApiInfo(
properties.getTitle(),
properties.getDescription(),
properties.getVersion(),
properties.getTermsOfServiceUrl(),
contact,
properties.getLicense(),
properties.getLicenseUrl(),
new ArrayList<>()
);
docket.host(properties.getHost())
.protocols(new HashSet<>(Arrays.asList(properties.getProtocols())))
.securitySchemes(Arrays.asList((apiKey())))
.securityContexts(Arrays.asList(
SecurityContext.builder()
.securityReferences(
Arrays.asList(SecurityReference.builder()
.reference("JWT")
.scopes(new AuthorizationScope[0])
.build()
)
)
.build())
)
.apiInfo(apiInfo)
.useDefaultResponseMessages(properties.isUseDefaultResponseMessages())
.forCodeGeneration(true)
.directModelSubstitute(ByteBuffer.class, String.class)
.genericModelSubstitutes(ResponseEntity.class)
.ignoredParameterTypes(Pageable.class)
.select()
.paths(regex(properties.getDefaultIncludePattern()))
.build();
watch.stop();
log.debug(STARTED_MESSAGE, watch.getTotalTimeMillis());
return docket;
}
/**
* Springfox configuration for the management endpoints (actuator) Swagger docs.
*
* #param appName the application name
* #param managementContextPath the path to access management endpoints
* #return the Swagger Springfox configuration
*/
#Bean
#ConditionalOnMissingBean(name = "swaggerSpringfoxManagementDocket")
public Docket swaggerSpringfoxManagementDocket(#Value("${spring.application.name:application}") String appName,
#Value("${management.endpoints.web.base-path}") String managementContextPath) {
ApiInfo apiInfo = new ApiInfo(
StringUtils.capitalize(appName) + " " + MANAGEMENT_TITLE_SUFFIX,
MANAGEMENT_DESCRIPTION,
properties.getVersion(),
"",
ApiInfo.DEFAULT_CONTACT,
"",
"",
new ArrayList<>()
);
return createDocket()
.apiInfo(apiInfo)
.useDefaultResponseMessages(properties.isUseDefaultResponseMessages())
.groupName(MANAGEMENT_GROUP_NAME)
.host(properties.getHost())
.protocols(new HashSet<>(Arrays.asList(properties.getProtocols())))
.securitySchemes(Arrays.asList((apiKey())))
.securityContexts(Arrays.asList(
SecurityContext.builder()
.securityReferences(
Arrays.asList(SecurityReference.builder()
.reference("JWT")
.scopes(new AuthorizationScope[0])
.build()
)
)
.build())
)
.forCodeGeneration(true)
.directModelSubstitute(ByteBuffer.class, String.class)
.genericModelSubstitutes(ResponseEntity.class)
.ignoredParameterTypes(Pageable.class)
.select()
.paths(regex(managementContextPath + ".*"))
.build();
}
protected Docket createDocket() {
return new Docket(DocumentationType.SWAGGER_2);
}
private ApiKey apiKey() {
return new ApiKey("JWT", AUTHORIZATION_HEADER, ApiKeyVehicle.HEADER.getValue());
}
} // END
At first i got a similar problem like yours and i searched to find your post.
But my project uses .net core,and from the url below i found a solution.
Hope it could help you if you haven't got your problem fixed.
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#add-security-definitions-and-requirements
I've been starting to use GraphAware timetree for neo4j, and so far its working out pretty well. Now I'm trying to work out how I can unit / integration test my code that uses neo4j timetree.
I've put together some code as below... but still I'm getting the message:
org.neo4j.ogm.exception.CypherException: Error executing Cypher "Neo.ClientError.Procedure.ProcedureNotFound"; Code: Neo.ClientError.Procedure.ProcedureNotFound; Description: There is no procedure with the name `ga.timetree.events.attach` registered for this database instance. Please ensure you've spelled the procedure name correctly and that the procedure is properly deployed.
Am I sort of on the right track?
package myproject.core;
import java.util.ArrayList;
import java.util.HashMap;
import javax.inject.Inject;
import org.junit.After;
import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.testutil.MultiDriverTestClass;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.test.context.junit4.SpringRunner;
import com.graphaware.common.policy.NodeInclusionPolicy;
import com.graphaware.module.timetree.module.TimeTreeConfiguration;
import com.graphaware.module.timetree.module.TimeTreeModule;
import com.graphaware.runtime.GraphAwareRuntime;
import com.graphaware.runtime.GraphAwareRuntimeFactory;
import myproject.core.context.TestPersistenceContext;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = TestPersistenceContext.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AbstractTest extends MultiDriverTestClass {
#Inject
private Neo4jOperations neo4jOperations;
public AbstractTest() {
new SessionFactory("myproject.model.pojos").openSession();
TimeTreeConfiguration timeTreeConfiguration = TimeTreeConfiguration.defaultConfiguration();
TimeTreeModule timeTreeModule = new TimeTreeModule("TT.1", timeTreeConfiguration, super.getGraphDatabaseService());
GraphAwareRuntime runtime = GraphAwareRuntimeFactory.createRuntime(super.getGraphDatabaseService());
runtime.registerModule(timeTreeModule);
runtime.start();
}
#After
public void clearDatabase() {
neo4jOperations.query("match (n) detach delete n;", new HashMap<>());
neo4jOperations.clear();
}
}
Please change your AbstractTest() constructor to read as follows:
public AbstractTest() {
new SessionFactory("myproject.model.pojos").openSession();
TimeTreeConfiguration timeTreeConfiguration = TimeTreeConfiguration.defaultConfiguration();
TimeTreeModule timeTreeModule = new TimeTreeModule("TT.1", timeTreeConfiguration, super.getGraphDatabaseService());
TimeTreeProcedures.register(super.getGraphDatabaseService());
GraphAwareRuntime runtime = GraphAwareRuntimeFactory.createRuntime(super.getGraphDatabaseService());
runtime.registerModule(timeTreeModule);
runtime.start();
}
Note the added line: TimeTreeProcedures.register(super.getGraphDatabaseService());
I'm new to Spring and I try to create a secured rest application using Spring Boot and Spring Security. I'm searching for weeks for a solution now...
I'm using Spring Boots embedded web container (Tomcat) and the spring-boot-starter-parent 1.2.6.RELEASE in my pom.
My endpoints:
/login (to authenticate)
/application/{id} (some service which I want to secure)
I configured my servlet path in my application.properties like this:
server.servletPath: /embedded
so I expect my services e.g. on //localhost/embedded/login
Ok so now the problem: If I run the application without security everything is fine, I can call http//localhost/embedded/application and get an answer.
If I now add my security configuration like this:
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebMvcSecurity
#EnableScheduling
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Value("${server.servletPath}")
private String servletPath;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/hello/**", "/login").permitAll()
.antMatchers("/application/**").authenticated().and()
.addFilterBefore(new TokenAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.httpBasic().disable();
}
}
when running the application //localhost/application/{id} is secured instead of
//localhost/embedded/application/{id} as I would have expected.
For some reason the servlet path is ignored there. I tought "ok so I just add the servlet path manually" and make it look like this:
...antMatchers(servletPath+"/application/**").authenticated()...
This works in my application. However I also use MockMvc to test my services and for some reason there the servlet path is correctly added to the matchers. So if I start the tests the security filters are mapped to //localhost/embedded/embedded/application/{id} while the controllers themselves still are mapped to //localhost/embedded/application/{id} which is very annoying...
I took a look at here http://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security/ and thought I could fix the issue by using AbstractSecurityWebApplicationInitializer instead of SpringBootServletInitializer but it changed nothing.
This is my application class by the way:
com.sebn.gsd.springservertemplate.service.security.WebSecurityConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
System.out.println("Run from main");
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass, WebSecurityConfig.class);
}
private static Class<Application> applicationClass = Application.class;
}
The application.properties doesn't contain any more interesting information I think. To be complete this is my MockMvc testing class:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sebn.gsd.springservertemplate.service.api.LoginData;
import com.sebn.gsd.springservertemplate.service.security.Session_model;
import com.sebn.gsd.springservertemplate.service.security.WebSecurityConfig;
import java.util.Arrays;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.notNullValue;
import org.junit.Assert;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.web.servlet.ResultActions;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
import org.springframework.web.context.WebApplicationContext;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {Application.class, WebSecurityConfig.class })
#WebAppConfiguration
#ActiveProfiles(profiles = "development")
public class SecurityTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private HttpMessageConverter mappingJackson2HttpMessageConverter;
private ObjectMapper o = new ObjectMapper();
#Autowired
private FilterChainProxy filterChainProxy;
#Value("${server.servletPath}")
private String servletPath;
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext).addFilter(filterChainProxy).build();
}
#Test
public void testLoginSecurity() throws Exception {
int applicationId = 1;
// Try to access secured api
ResultActions actions = mockMvc.perform(get("/application/" + applicationId))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isForbidden());
//login
String username = "user";
LoginData loginData = new LoginData();
loginData.setPasswordBase64("23j4235jk26=");
loginData.setUsername(username);
actions = mockMvc.perform(post("/login").content(o.writeValueAsString(loginData)).contentType(MediaType.APPLICATION_JSON_VALUE))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.login", Matchers.equalTo(username)))
.andExpect(jsonPath("$.token", notNullValue()))
.andExpect(jsonPath("$.expirationDate", notNullValue()));
Session_model session = getResponseContentAsJavaObject(actions.andReturn().getResponse(), Session_model.class);
Assert.assertNotNull(session);
// Try to access secured api again
actions = mockMvc.perform(get("/application/" + applicationId).header("X-AUTH-TOKEN", session.getToken()))
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isOk());
}
private <T> T getResponseContentAsJavaObject(MockHttpServletResponse response, Class<T> returnType) throws Exception{
return o.readValue(response.getContentAsString(), returnType);
}
#Autowired
void setConverters(HttpMessageConverter<?>[] converters) {
this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter(
hmc -> hmc instanceof MappingJackson2HttpMessageConverter).findAny().get();
Assert.assertNotNull("the JSON message converter must not be null",
this.mappingJackson2HttpMessageConverter);
}
}
Maybe I misunderstood something. I hope you can tell me.
Summary
In short you need to map Spring Security to use include the servlet path. Additionally, you need to include the servlet path in your MockMvc requests. To do so you can perform something like:
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext)
// ADD LINE BELOW!!!
.defaultRequest(get("/").servletPath(servletPath))
.addFilter(filterChainProxy)
.build();
}
Detailed Response
Spring Security Matches Based on Context Root
Spring Security's matchers are relative to the application's context root. It is not relative to the servlet path. This is deliberate because it should protect all the servlets (not just Spring MVC). If it were relative to the servlet, consider the following:
servlet1-path/abc -> Only users with role ROLE_ADMIN can access
servlet2-path/abc -> Only users with role ROLE_USER can access
How would you differentiate between these two mappings if Spring Security were relative to the servlet path?
Working in Mock MVC
The reason Spring Security is working in MockMvc is because when you are using MockMvc the servlet path is no longer considered. Your requests are being sent to Spring Security and Spring MVC as though the servlet path is "". To fix this you need to include the servlet path in the request.
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext)
// ADD LINE BELOW!!!
.defaultRequest(get("/").servletPath(servletPath))
.addFilter(filterChainProxy)
.build();
}
I am building an android app that uses youtube API. I have figured the flow with youtube API but i don't know how start building it in java.I am completely new to using API's.Can anyone please provide a direction?
Please follow this approach. First you should try to download the Youtube player library for Android from the link below:
Youtube Android Player
You should first install it like this: Project -> menu: File > Structure > Dependencies Tab > Add -> library dependency
if it doesn't work, please try one of these two:
Add dependency of the library inside dependency inside build.gradle file of the library u r using, and paste ur library in External Libraries.
OR
Just Go to your libs folder inside app folder and paste all your .jar e.g Library files there Now the trick here is that now go inside settings.gradle file now add this line include ':app:libs' after include ':app' It will definitely work.
Then, you should have a layout like this:
<com.google.android.youtube.player.YouTubePlayerView
android:id="#+id/player_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
And you can have a player activity like this:
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import java.io.IOException;
public class YoutubeActivity extends YouTubeBaseActivity{
private YouTubePlayerView playerView;
private YouTube youtube;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_youtube);
youtube = new YouTube.Builder(new NetHttpTransport(),
new JacksonFactory(), new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest hr) throws IOException {}
}).setApplicationName(this.getString(R.string.app_name)).build();
playerView = (YouTubePlayerView)findViewById(R.id.player_view);
playerView.initialize("Your API Key", new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
if(!b){
String videoId = getIntent().getExtras().getString("videoID");
youTubePlayer.cueVideo(videoId);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
Toast.makeText(getApplicationContext(), getString(R.string.failed), Toast.LENGTH_LONG).show();
}
});
}
}