[SalesForce] How to navigate to sobject record from Lightning Component in Visualforce page (ltng:outApp)

In Lightning Experience, I have a custom URL button on Opportunity object that references a Visualforce page that surfaces a Lightning Component.

The Lightning Component has a "Cancel" button that when clicked I want to navigate back to the Opportunity record.

The challenge I'm having is I'm not sure how to do this.

MyComponent.cmp

<lightning:button aura:id="cancelButton"
                  name="cancelButton"
                  label="Cancel"
                  variant="neutral"
                  onclick="{!c.onClickCancelButton}"/>

MyComponentController.js

onClickCancelButton : function(component, event, helper) {

    console.log( 'onClickCancelButton' );

    var recordId = component.get( 'v.recordId' );

    var event = $A.get( 'e.force:navigateToSObject' );

    if ( event ) {

        // I never get here, the event isn't available
        // from Visualforce context even though I'm rendering in LEX

        event.setParams({
            'recordId' : recordId
        }).fire();

    } else {

        // since no event to fire for navigation, what else can I do?

        // LockerService blocks modifying window.location

        // Monkeying with window.location.pathname only loads a Classic page nested in LEX


    }

}

Lightning Out Visualforce Page

<apex:page>

    <apex:includeLightning />

    <div id="container"/>

    <script>

        $Lightning.use( "c:MyLightningOutApp", function() {

            var recordId = '{!$CurrentPage.parameters.recordId}';

            $Lightning.createComponent(
                'c:MyComponent',
                {
                    'recordId' : recordId
                },
                'container',
                function( component ) {

                }
            );

        });

    </script>

</apex:page>

Best Answer

I have found the following to work in my VF pages when transitioning to LEX:

(function(myContext){
    myContext.ForceUI = myContext.ForceUI || {};

    myContext.ForceUI.isSalesforce1 = function() {
        return((typeof sforce != 'undefined') && sforce && (!!sforce.one));
    }
})(this);

Then you can use (as an example):

ForceUI.isSalesforce1() ? navigateToSObject(aId) : (window.location.href='/' + aId);

https://developer.salesforce.com/docs/atlas.en-us.salesforce1.meta/salesforce1/vf_dev_best_practices_pages_multipurpose.htm

Also, see my answer here for a template to use to navigate as needed and make it easy to transition your VF pages:

What is suggested approach to transfer VF pages to be lightning ready