Skip to main content
11 of 12
deleted 104 characters in body
Kuba
  • 138.9k
  • 13
  • 297
  • 803

There are some doubts about using SaveDefinitions (1), (2), so let's implement a brute force approach which may be later used automatically.


Outline

Needs @ yourPackage (*a*) CDFDeploy @ With[ { source = Import[packagePath] (*b*) } , DynamicModule[ { ... } , ... , Initialization :> ( Get @ StringToStream @ source ) ] 
  • (a). You have to call you package before creating DynamicModule because you need all static content (not held/dynamic) in the body of DM to be parsed and evaluated properly.

And all dynamic/held names to be "typeset" with proper context name. And they will be found thanks to $ContextPath modified by BeginPackage and friends. (3)

  • (b). We have to use With to inject source into DynamicModule's Initialization because Initialization is set with RuleDelayed which is HoldRest.

  • For more complex/time consuming packages you may want to change SynchronousInitialization->False and monitor the state of initialization analogously to:

Working with DynamicModule: Tracking the progress of Initialization


###Execution

First code block is only to create a test package:

content = " BeginPackage[\"TestPackage`\"] f::usage=\"f[x] returns a plot.\"; Begin[\"`Private`\"] f[x_]:=Plot[Sin[x y],{y,0,2 Pi},PlotRange->{-1,1},ImageSize->500] End[] EndPackage[]"; path = FileNameJoin[{$TemporaryDirectory, "package.m"}]; pathEnc = FileNameJoin[{$TemporaryDirectory, "package.enc"}]; pathCDF = FileNameJoin[{$TemporaryDirectory, "CDF.cdf"}] Export[path, content, "Text"]; 

Now the actual code:

Encode[path, pathEnc]; (*c*) encodedpackage = Import[pathEnc, "Text"]; Get @ pathEnc (*a*) CDFDeploy[ pathCDF, #, Method -> "Standalone", "Target" -> "CDFPlayer" ] & @ With[ { source = encodedpackage (*b*) } , DynamicModule[{x = 1} , Column[{ Dynamic[{x, f[x]}], Button["x++", x++], Dynamic @ $ContextPath }] , Initialization :> Module[{stream} , stream = StringToStream @ source ; Get @ stream ; Close @ stream ] ] ] 

c. we are Encoding source, it is then obscure for others and already compressed so why not. You can even incorporate password protection with this method: (4). It won't be fully secure, as pointed in comments here: (5).

You can now go to the CDF and test in the FreePlayer:

SystemOpen @ DirectoryName @ pathCDF 

enter image description here


###Links

(1) The dangers of SaveDefinitions

(2) Not FullDefinition for Save. MachineID not Protected?

(3) load a Mathematica package inside a DynamicModule

(4) Encode->Import->StringToStream->Get on password-locked stream

(5) How to create protected single-file stand-alone CDF applications

Kuba
  • 138.9k
  • 13
  • 297
  • 803